home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / ddj1190.arc / WILLIAMS.ASC < prev   
Text File  |  1990-10-27  |  87KB  |  2,700 lines

  1. _ROLL YOUR OWN DOS EXTENDER_
  2. by Al Williams
  3.  
  4. [LISTING ONE]
  5.  
  6. ;********************************************************************
  7. ;* PROT - A 386 protected mode DOS extender                         *
  8. ;* Copyright (C) 1989, by Al Williams  All rights reserved.         *
  9. ;* Permission is granted for non-commercial use of this software.   *
  10. ;* You are expressly prohibited from selling this software,         *
  11. ;* distributing it with another product, or removing this notice.   *
  12. ;* If you distribute this software to others in any form, you must  *
  13. ;* distribute all of the files that are listed below:               *
  14. ;* PROT.ASM     - The main routines and protected mode support.     *
  15. ;* EQUMAC.INC   - Equates and macros.                               *
  16. ;* STACKS.INC   - Stack segments.                                   *
  17. ;* GDT.INC      - Global descriptor table.                          *
  18. ;* INT386.INC   - Protected mode interrupt handlers.                *
  19. ;* PMDEMO.PM    - Example user code.                                *
  20. ;* PMPWD.PM     - Alternate example code.                           *
  21. ;* FBROWSE.PM   - Complete sample application.                      *
  22. ;* TSS.INC      - Task state segments.                              *
  23. ;* CODE16.INC   - 16 bit DOS code (entry/exit).                     *
  24. ;* PMASM.BAT    - MASM driver for assembling PROT programs.         *
  25. ;* To assemble:    MASM /DPROGRAM=pname PROT.ASM,,PROT.LST;         *
  26. ;* To link:        LINK PROT;                                       *
  27. ;*      pname is the program name (code in pname.PM)                *
  28. ;*      if pname is ommited, USER.PM is used                        *
  29. ;* The resulting .EXE file is executable from the DOS prompt.       *
  30. ;* This file is: PROT.ASM, the main protected mode code.            *
  31. ;********************************************************************
  32.  
  33. .XLIST
  34. .LALL
  35.  
  36. .386P
  37.  
  38. ; Name program if PROGRAM is defined
  39. IFDEF        PROGRAM
  40. VTITLE       MACRO    PNAME        ; temporary macro to title program
  41.              TITLE    PNAME
  42.              ENDM
  43.              VTITLE   %PROGRAM
  44.              PURGE    VTITLE       ; delete macro
  45. ; equates and macros
  46. INCLUDE      EQUMAC.INC
  47.  
  48. ; stack segments
  49. INCLUDE      STACKS.INC
  50.  
  51. ; Global descriptor table definitons
  52. INCLUDE      GDT.INC
  53.  
  54. ; interrupt code
  55. INCLUDE      INT386.INC
  56.  
  57. ; this is required to find out how large PROT is
  58. ZZZGROUP     GROUP    ZZZSEG
  59.  
  60. ;********************************************************************
  61. ; 32 bit data segment
  62. DAT32        SEGMENT  PARA PUBLIC 'DATA32' USE32
  63. DAT32BEG     EQU      $
  64.  
  65. ; 32 bit stack values
  66. SLOAD        DD       OFFSET SSEG321-1
  67. SSLD         DW       SEL_STACK
  68.  
  69. ; This location will hold the address for the PMODE IDT
  70. NEWIDT       EQU      THIS FWORD
  71.              DW       (IDTEND-IDTBEG)-1
  72. IDTB         DD       0            ; filled in at runtime
  73.  
  74. ; PSP segment address
  75. _PSP         DW       0
  76.  
  77. ; video variables for the OUCH and related routines
  78. CURSOR       DD       0            ; cursor location
  79. COLOR        DB       7            ; display cursor
  80.  
  81. ; temp vars for some non reentrant interrupt routines
  82. STO1         DD       0
  83. STO2         DD       0
  84. STO3         DD       0
  85. STO4         DD       0
  86. SAV_DS       DD       0
  87. SAV_ES       DD       0
  88. SAV_GS       DD       0
  89. SAV_FS       DD       0
  90.  
  91. BPON         DB       0            ; Enables conditional breakpoints
  92.  
  93. ; Debug Dump variables
  94. DUMP_SEG     DW       0            ; if zero don't dump memory
  95. DUMP_OFF     DD       0            ; Offset to start at
  96. DUMP_CNT     DD       0            ; # of bytes to dump
  97.  
  98. ; Break & critical error handler variables
  99. BREAKKEY     DB       0            ; break key occurred
  100. CRITICAL     DB       0            ; critical error occured
  101. CRITAX       DW       0            ; critical error ax
  102. CRITDI       DW       0            ; critical error di
  103. CRITBP       DW       0            ; critical error bp
  104. CRITSI       DW       0            ; critical error si
  105.  
  106. ; Address of user's break handler
  107. BREAK_HANDLE EQU      THIS FWORD
  108. BRK_OFF      DD       0
  109. BRK_SEG      DW       0
  110.  
  111. ; Address of user's critical error handler
  112. CRIT_HANDLE  EQU      THIS FWORD
  113. CRIT_OFF     DD       OFFSET DEF_CRIT
  114. CRIT_SEG     DW       SEL_CODE32
  115.  
  116. ; Message for default critical error handler
  117. CRITMSG      DB       'A critical error has occured.',13,10
  118.              DB       '<A>bort, <R>etry, <F>ail? $'
  119.  
  120. ; here is where vm86 int's stack up pl0 esp's
  121. INTSP        DD       $+PVSTACK+4
  122.              DB       PVSTACK DUP (0)
  123.  
  124. ; Default VM86CALL parameter block
  125. PINTFRAME    VM86BLK  <>
  126.  
  127. ; interface block for critical error handler
  128. CINTFRAME    VM86BLK  <>
  129.  
  130. ; hardware interrupt vm86 block
  131. HINTFRAME    VM86BLK  <>
  132.  
  133. ; storage for the original PIC interrupt mask registers
  134. INTMASK      DB       0
  135. INTMASKAT    DB       0
  136.  
  137. DAT32END     EQU      $
  138. DAT32        ENDS
  139.  
  140. ;********************************************************************
  141. ; Begin 32 bit code segment
  142.  
  143. SEG32        SEGMENT  PARA PUBLIC 'CODE32' USE32
  144.              ASSUME   CS:SEG32, DS:DAT32
  145. PCODE        PROC
  146. SEG32BEG     EQU      $
  147.  
  148. ; Start of protected mode code. We jump here from inside CODE16.INC
  149. SEG32ENT:    MOV      AX,SEL_DATA  ; 1st order of business:
  150.              MOV      DS,AX        ; load up segment registers
  151.              LSS      ESP, FWORD PTR SLOAD
  152.              MOV      AX,SEL_VIDEO
  153.              MOV      ES,AX
  154.              MOV      AX,SEL_DATA0
  155.              MOV      FS,AX
  156.              MOV      AX,SEL_GDT
  157.              MOV      GS,AX
  158. ; set up IDT
  159.              CALL32S  MAKIDT
  160. ; reprogram pic(s)
  161.              IN       AL,21H
  162.              MOV      INTMASK,AL
  163. IF           ATCLASS
  164.              IN       AL,0A1H
  165.              MOV      INTMASKAT,AL
  166.              MOV      AL,11H
  167.              OUT      0A0H,AL
  168.              OUT      20H,AL
  169.              IDELAY
  170.              MOV      AL,28H
  171.              OUT      0A1H,AL
  172.              MOV      AL,20H
  173.              OUT      21H,AL
  174.              IDELAY
  175.              MOV      AL,2
  176.              OUT      0A1H,AL
  177.              MOV      AL,4
  178.              OUT      21H,AL
  179.              IDELAY
  180.              MOV      AL,1
  181.              OUT      0A1H,AL
  182.              OUT      21H,AL
  183.              IDELAY
  184.              MOV      AL,INTMASKAT
  185.              OUT      0A1H,AL
  186.              MOV      AL,INTMASK
  187.              OUT      21H,AL
  188. ELSE
  189. ; INBOARD PC Code
  190.              MOV      AL,13H
  191.              OUT      20H,AL
  192.              MOV      AL,20H
  193.              OUT      21H,AL
  194.              MOV      AL,9
  195.              OUT      21H,AL
  196.              MOV      AL,INTMASK
  197.              OUT      21H,AL
  198. ENDIF
  199.              STI                   ; enable interrupts
  200.  
  201. ; *** Start user code with TSS (req'd for vm86 op's etc.)
  202.              MOV      AX,TSS0
  203.              LTR      AX
  204.              JMPABS32 TSS1,0
  205. PCODE        ENDP
  206.  
  207. ;*** 32 bit support routines
  208. ; This routine creates the required IDT. This is only a subroutine to keep 
  209. ; from cluttering up the main code, since you aren't likely to call it again.
  210. ; Assumes that all ISR routines are of fixed length and in sequence. After 
  211. ; makidt has built the table, you can still replace individual INT gates with 
  212. ; your own gates (see make_gate)
  213. MAKIDT       PROC     NEAR
  214.              PUSH     ES
  215.              MOV      AX,IDTABLE
  216.              MOVZX    EAX,AX
  217.              SHL      EAX,4
  218.              ADD      EAX,OFFSET IDTBEG
  219.              MOV      IDTB,EAX
  220.              MOV      AX,SEL_IDT
  221.              MOV      ES,AX
  222.              XOR      AL,AL
  223. ; Make all interrupt gates DPL=3
  224.              MOV      AH,INTR_GATE OR DPL3
  225.              MOV      CX,SEL_ICODE
  226.              MOV      EDX,OFFSET IDTBEG
  227.              XOR      SI,SI
  228.              MOV      EBX,OFFSET INT0
  229. IDTLOOP:     CALL32F  SEL_CODE32,MAKE_GATE
  230.              ADD      EBX,INT1-INT0
  231.              ADD      SI,8
  232. ; loop form max # of interrupts
  233.              CMP      SI,(TOPINT+1)*8
  234.              JB       SHORT IDTLOOP
  235.              LIDT     NEWIDT
  236.              POP      ES
  237.              RET
  238. MAKIDT       ENDP
  239.  
  240. ; This routine is just like the real mode make_desc
  241. ; EBX=base  ECX=limit   AH=ARB  AL=0 or 1 for 16 or 32 bit
  242. ; SI=selector (TI&RPL ignored) and ES:EDX is the table base address
  243. MAKE_SEG     PROC     FAR
  244.              PUSH     ESI
  245.              PUSH     EAX
  246.              PUSH     ECX
  247.              MOVZX    ESI,SI
  248.              SHR      SI,3         ; adjust to slot #
  249.              SHL      AL,6         ; shift size to right bit position
  250.              CMP      ECX,0FFFFFH  ; see if you need to set G bit
  251.              JLE      OKLIM
  252.              SHR      ECX,12       ; div by 4096
  253.              OR       AL,80H       ; set G bit
  254. OKLIM:       MOV      ES:[EDX+ESI*8],CX
  255.              SHR      ECX,16
  256.              OR       CL,AL
  257.              MOV      ES:[EDX+ESI*8+6],CL
  258.              MOV      ES:[EDX+ESI*8+2],BX
  259.              SHR      EBX,16
  260.              MOV      ES:[EDX+ESI*8+4],BL
  261.              MOV      ES:[EDX+ESI*8+5],AH
  262.              MOV      ES:[EDX+ESI*8+7],BH
  263.              POP      ECX
  264.              POP      EAX
  265.              POP      ESI
  266.              RET
  267. MAKE_SEG     ENDP
  268.  
  269. ; This routine make gates -- AL=WC if applicable -- AH=ARB  -- EBX=offset 
  270. ; CX=selector  -- ES:EDX=table base  --  SI= selector (TI&RPL ignored)
  271. MAKE_GATE    PROC     FAR
  272.              PUSH     ESI
  273.              PUSH     EBX
  274.              SHR      SI,3
  275.              MOVZX    ESI,SI
  276.              MOV      ES:[EDX+ESI*8],BX
  277.              MOV      ES:[EDX+ESI*8+2],CX
  278.              MOV      ES:[EDX+ESI*8+4],AX
  279.              SHR      EBX,16
  280.              MOV      ES:[EDX+ESI*8+6],BX
  281.              POP      EBX
  282.              POP      ESI
  283.              RET
  284. MAKE_GATE    ENDP
  285.  
  286. ; Routine to call BIOS/DOS. NOT REENTRANT (but so what? DOS isn't either)
  287. CALL86       PROC     FAR
  288.              PUSH     DS
  289.              PUSH     GS
  290.              PUSH     FS
  291. RETRY86:
  292.              PUSHAD
  293.              PUSHFD
  294.              PUSH     ES:[EBX+40]  ; save new ebx
  295.              PUSH     EBX
  296.              PUSH     ES
  297.              INT      30H          ; call PROT
  298.              PUSH     SEL_DATA
  299.              POP      DS
  300.              POP      ES
  301.              XCHG     EBX,[ESP]
  302.              POP      ES:[EBX+40]
  303.              PUSHFD
  304.              CMP      BREAKKEY,0   ; see if break occured
  305.              JZ       SHORT NOBRKCHECK
  306.              CMP      BRK_SEG,0    ; see if user has brk handler
  307.              JZ       SHORT NOBRKCHECK
  308.                                    ; call user's break handler
  309.              MOV      BREAKKEY,0
  310.              CALL     FWORD PTR BREAK_HANDLE
  311. NOBRKCHECK:
  312.              CMP      CRITICAL,0   ; see if critical error
  313.              JZ       SHORT NOCRITCK
  314.              CMP      CRIT_SEG,0   ; see if critical error handler
  315.              JZ       SHORT NOCRITCK
  316.                                    ; call critical error handler
  317.              PUSH     EAX
  318.              XOR      AL,AL
  319.              MOV      CRITICAL,AL
  320.              CALL     FWORD PTR CRIT_HANDLE
  321.              OR       AL,AL        ; AL=0? FAIL
  322.              JNZ      SHORT RETRY?
  323.              POP      EAX
  324.              POPFD
  325.              STC                   ; make sure carry is set
  326.              PUSHFD
  327.              JMP      SHORT NOCRITCK
  328. RETRY?:      DEC      AL           ; AL=1? RETRY
  329.              JNZ      SHORT CABORT
  330. ; To retry an error, we set up everything the way it was and
  331. ; redo the interrupt. This is cheating (a little), and may not
  332. ; work in every possible case, but it seems to work in all the cases tried.
  333.              POP      EAX
  334.              POPFD
  335.              POP      ES:[EBX+40]
  336.              POPFD
  337.              POPAD
  338.              JMP      SHORT RETRY86
  339. CABORT:      POP      EAX          ; ABORT
  340.              POPFD
  341.              LEA      ESP,[ESP+40] ; balance stack
  342.              MOV      AL,7FH       ; DOS error=7FH
  343.              BACK2DOS
  344. NOCRITCK:
  345.              POPFD
  346.              LEA      ESP,[ESP+40] ; balance stack
  347.              PUSHFD
  348. ; see if segment save requested
  349.              CMP      BYTE PTR ES:[EBX],0
  350.              JZ       NOSEGS
  351. ; load parameter block from static save area
  352.              PUSH     EAX
  353.              MOV      EAX,SAV_FS
  354.              MOV      ES:[EBX+28],EAX
  355.              MOV      EAX,SAV_DS
  356.              MOV      ES:[EBX+24],EAX
  357.              MOV      EAX,SAV_ES
  358.              MOV      ES:[EBX+20],EAX
  359.              MOV      EAX,SAV_GS
  360.              MOV      ES:[EBX+32],EAX
  361.              POP      EAX
  362. NOSEGS:
  363.              POPFD
  364.              POP      FS
  365.              POP      GS
  366.              POP      DS
  367.              MOV      EBX,ES:[EBX+40]
  368.              RET
  369. CALL86       ENDP
  370.  
  371. ; Directly clear page 0 of the screen
  372. CLS          PROC     FAR
  373.              PUSHFD
  374.              PUSH     DS
  375.              PUSH     ES
  376.              PUSH     EDI
  377.              PUSH     ECX
  378.              PUSH     EAX
  379.              MOV      CX,SEL_VIDEO
  380.              MOV      ES,CX
  381.              MOV      CX,SEL_DATA
  382.              MOV      DS,CX
  383.              CLD
  384.              MOV      EDI,0
  385.              MOV      ECX,2000
  386.              MOV      AX,0720H
  387.              REP      STOSW
  388.              XOR      ECX,ECX
  389.              MOV      CURSOR,ECX
  390.              POP      EAX
  391.              POP      ECX
  392.              POP      EDI
  393.              POP      ES
  394.              POP      DS
  395.              POPFD
  396.              RET
  397. CLS          ENDP
  398.  
  399. ; Outputs message to screen -- ASCIIZ pointer in ds:ebx - modifies ebx
  400. MESSOUT      PROC     FAR
  401.              PUSH     EAX
  402. NXT:         MOV      AL,[EBX]
  403.              INC      EBX
  404.              OR       AL,AL
  405.              JNZ      SHORT SKIP
  406.              POP      EAX
  407.              RET
  408. SKIP:        CALL32F  SEL_CODE32, OUCH
  409.              JMP      SHORT NXT
  410. MESSOUT      ENDP
  411.  
  412. ; Performs CR/LF sequence to screen using OUCH
  413. CRLF         PROC     FAR
  414.              PUSH     EAX
  415.              MOV      AL,13
  416.              CALL32F  SEL_CODE32,OUCH
  417.              MOV      AL,10
  418.              CALL32F  SEL_CODE32,OUCH
  419.              POP      EAX
  420.              RET
  421. CRLF         ENDP
  422.  
  423. ; Character and digit output routines 
  424. ; hexout4 - print longword in EAX in hex
  425. ; hexout2 - print word in AX in hex
  426. ; hexout  - print byte in AL in hex
  427. ; ouch    - print ASCII character in AL
  428. OUTPUT       PROC     FAR
  429. ; print longword in eax
  430. HEXOUT4      LABEL    FAR
  431.              PUSH     EAX
  432.              SHR      EAX,16
  433.              CALL32F  SEL_CODE32,HEXOUT2
  434.              POP      EAX
  435. ; print word in ax
  436. HEXOUT2      LABEL    FAR
  437.              PUSH     EAX
  438.              MOV      AL,AH
  439.              CALL32F  SEL_CODE32, HEXOUT
  440.              POP      EAX
  441. ; print a hex byte in al
  442. HEXOUT       LABEL    FAR
  443.              MOV      BL,AL
  444.              AND      AX,0F0H
  445.              SHL      AX,4
  446.              MOV      AL,BL
  447.              AND      AL,0FH
  448.              ADD      AX,'00'
  449.              MOV      BL,AL
  450.              MOV      AL,AH
  451.              CALL32F  SEL_CODE32, HEX1DIG
  452.              MOV      AL,BL
  453. HEX1DIG:     CMP      AL,'9'
  454.              JBE      SHORT H1DIG
  455.              ADD      AL,'A'-'0'-0AH
  456. H1DIG:
  457. OUCH         LABEL    FAR
  458.              PUSH     EDI
  459.              PUSH     EAX
  460.              PUSH     DS
  461.              PUSH     ES
  462.              PUSH     ECX
  463.              MOV      CX,SEL_VIDEO
  464.              MOV      ES,CX
  465.              MOV      CX,SEL_DATA
  466.              MOV      DS,CX
  467.              POP      ECX
  468.              MOV      AH,COLOR
  469.              MOV      EDI,CURSOR
  470.              CMP      EDI,2000     ; rolling off the screen?
  471.              JB       NOSCROLL
  472. ; scroll screen if required
  473.              PUSH     DS
  474.              PUSH     ES
  475.              POP      DS
  476.              PUSH     ESI
  477.              PUSH     ECX
  478.              PUSH     EDI
  479.              CLD
  480.              MOV      ECX,960
  481.              XOR      EDI,EDI
  482.              MOV      ESI,160
  483.              REP      MOVSD
  484.              POP      EDI
  485.              SUB      EDI,80
  486.              POP      ECX
  487.              POP      ESI
  488.              POP      DS
  489. NOSCROLL:    CMP      AL,0DH
  490.              JZ       SHORT CR
  491.              CMP      AL,0AH
  492.              JZ       SHORT LF
  493. ; write to screen
  494.              MOV      ES:[EDI*2],AX
  495.              INC      EDI
  496.              JMP      SHORT OUCHD
  497. CR:          PUSH     EDX
  498.              PUSH     ECX
  499.              MOV      EAX,EDI
  500.              XOR      EDX,EDX
  501.              MOV      ECX,80
  502.              DIV      ECX
  503.              SUB      EDI,EDX
  504.              POP      ECX
  505.              POP      EDX
  506.              JMP      SHORT OUCHD
  507. LF:          ADD      EDI,50H
  508. OUCHD:       MOV      CURSOR,EDI   ; update cursor
  509.              POP      ES
  510.              POP      DS
  511.              POP      EAX
  512.              POP      EDI
  513.              RET
  514. OUTPUT       ENDP
  515. ; Default critical error handler
  516. DEF_CRIT     PROC     FAR
  517.              PUSH     ES
  518.              PUSH     EBX
  519.              PUSH     EDX
  520.              MOV      BX,SEL_DATA
  521.              MOV      ES,BX
  522.              ASSUME   DS:NOTHING, ES:DAT32
  523. ; load critical error handler's private stack
  524.              MOV      BX,CSTACK
  525.              MOV      CINTFRAME.VMSS,EBX
  526.              MOV      EBX,OFFSET CSTACK
  527.              MOV      CINTFRAME.VMESP,EBX
  528.              MOV      BX,DAT32
  529.              MOV      CINTFRAME.VMDS,EBX
  530.              MOV      BX,21H
  531.              MOV      CINTFRAME.VMINT,EBX
  532.              MOV      EBX, OFFSET CINTFRAME
  533.              MOV      EDX,OFFSET CRITMSG
  534.              MOV      AH,9
  535.              PUSH     EBX
  536.              VM86CALL              ; print message
  537.              POP      EBX
  538. CLOOP:
  539.              MOV      AH,7
  540.              PUSH     EBX
  541.              VM86CALL              ; get keystroke
  542.              POP      EBX
  543. ; ignore function keys
  544.              OR       AL,AL
  545.              JZ       SHORT CRITFNKEY
  546.              MOV      AH,AL
  547.              OR       AL,20H       ; convert to lower case
  548.              CMP      AL,'a'
  549.              JNZ      SHORT CFAIL?
  550.              MOV      AL,2
  551.              JMP      SHORT CREXIT
  552. CFAIL?:      CMP      AL,'f'
  553.              JNZ      SHORT CRETRY?
  554.              XOR      AL,AL
  555.              JMP      SHORT CREXIT
  556. CRETRY?:
  557.              CMP      AL,'r'
  558.              MOV      AL,1
  559.              JNZ      SHORT CRITBAD
  560. CREXIT:      MOV      DL,AH        ; echo letter + CRLF
  561.              MOV      AH,2
  562.              PUSH     EAX
  563.              PUSH     EBX
  564.              VM86CALL
  565.              POP      EBX
  566.              MOV      AH,2
  567.              MOV      DL,0DH
  568.              PUSH     EBX
  569.              VM86CALL
  570.              POP      EBX
  571.              MOV      AH,2
  572.              MOV      DL,0AH
  573.              VM86CALL
  574.              POP      EAX
  575.              POP      EDX
  576.              POP      EBX
  577.              POP      ES
  578.              RET
  579. CRITFNKEY:
  580.              MOV      AH,7
  581.              PUSH     EBX
  582.              VM86CALL              ; ignore fn key/alt-key
  583.              POP      EBX
  584. CRITBAD:
  585.              MOV      DL,7
  586.              MOV      AH,2
  587.              PUSH     EBX
  588.              VM86CALL              ; unknown input - ring bell
  589.              POP      EBX
  590.              JMP      SHORT CLOOP
  591. DEF_CRIT     ENDP
  592.  
  593. SEG32END     EQU      $
  594. SEG32        ENDS
  595.  
  596. ;********************************************************************
  597. ; user program - PROT includes the file defined by the variable PROGRAM.
  598. ; convoluted method to make MASM take a string equate for an include filename
  599.  
  600. TEMPINCLUDE  MACRO    FN           ; ; temporary macro
  601.              INCLUDE  &FN&.PM
  602.              ENDM
  603. TEMPINCLUDE  %PROGRAM
  604.  
  605. PURGE        TEMPINCLUDE           ; delete macro
  606.  
  607. ; task state segments
  608. INCLUDE      TSS.INC
  609.  
  610. ; 16 bit code (DOS entry/exit)
  611. INCLUDE      CODE16.INC
  612.  
  613. ; Segment to determine the last memory address
  614. ZZZSEG       SEGMENT  PARA PUBLIC 'ZZZ' USE16
  615. ZZZSEG       ENDS
  616. ELSE
  617. IF2
  618.              %OUT     You must specify a program title
  619.              %OUT     use: MASM /DPROGRAM=PNAME PROT.ASM...
  620. ENDIF
  621.              .ERR
  622. ENDIF
  623.              END      ENTRY
  624.  
  625.  
  626. [LISTING TWO]
  627.  
  628. ;********************************************************************
  629. ;* PROT - A 386 protected mode DOS extender                         *
  630. ;* Copyright (C) 1989, by Al Williams -- All rights reserved.       *
  631. ;* Permission is granted for non-commercial use of this software    *
  632. ;* subject to certain conditions (see PROT.ASM).                    *
  633. ;* This file is: GDT.INC, the Global Descriptor Table definitions.  *
  634. ;********************************************************************
  635. ; See EQUMAC.INC for an explanation of the DESC macro
  636. GDTSEG       SEGMENT  PARA PUBLIC 'CODE32' USE32
  637. GDT          EQU      $            ; GDT space
  638.              DESC     SEL_NULL     ; DUMMY NULL SELECTOR
  639.              DESC     SEL_CODE16   ; 16 BIT CODE SEGMENT
  640.              DESC     SEL_DATA0    ; 4GB SEGMENT
  641.              DESC     SEL_CODE32   ; 32 BIT CODE SEGMENT
  642.              DESC     SEL_STACK    ; 32 BIT STACK
  643.              DESC     SEL_RDATA    ; REAL MODE LIKE DATA SEG
  644.              DESC     SEL_GDT      ; GDT ALIAS
  645.              DESC     SEL_VIDEO    ; VIDEO MEMORY
  646.              DESC     SEL_DATA     ; 32 BIT DATA
  647.              DESC     SEL_IDT      ; IDT ALIAS
  648.              DESC     SEL_ICODE    ; ISR SEGMENT
  649.              DESC     SEL_TSS0     ; DUMMY TASK BLOCK
  650.              DESC     TSS0         ; SAME (MUST FOLLOW SEL_TSS0)
  651.              DESC     SEL_TSS1     ; MAIN TASK BLOCK
  652.              DESC     TSS1         ; SAME (MUST FOLLOW SEL_TSS1)
  653.              DESC     SEL_UCODE    ; USER CODE
  654.              DESC     SEL_UDATA    ; USER DATA
  655.              DESC     SEL_PSP      ; DOS PSP
  656.              DESC     SEL_FREE     ; FREE DOS MEMORY
  657.              DESC     SEL_EXT      ; EXTENDED MEMORY
  658.              DESC     SEL_ENV      ; ENVIROMENT
  659. GDTEND       =        $
  660. GDTSEG       ENDS
  661.  
  662.  
  663. [LISTING THREE]
  664.  
  665. ;********************************************************************
  666. ;* PROT - A 386 protected mode DOS extender                         *
  667. ;* Copyright (C) 1989, by Al Williams -- All rights reserved.       *
  668. ;* Permission is granted for non-commercial use of this software    *
  669. ;* subject to certain conditions (see PROT.ASM).                    *
  670. ;* This file is: EQUMAC.INC, assorted macros and equates.           *
  671. ;********************************************************************
  672. ; EQUates the user may wish to change
  673. ATCLASS      EQU      1            ; 1=AT/386  0=INBOARD 386/PC
  674. DOSSTACK     EQU      200H         ; stack size for DOS startup
  675. VM86STACK    EQU      200H         ; stack size for VM86 int calls
  676. CRITSTACK    EQU      30H          ; stack size for crit err handler
  677. PMSTACK      EQU      1000H        ; stack size for p-mode stack
  678. PVSTACK      EQU      260          ; pl0/vm86 psuedo stack size
  679. ; Maximum protected mode interrupt # defined
  680.              TOPINT   EQU 30H
  681. ; The critical error handler works different for DOS 2.X than for other DOS 
  682. ; versions. In 99% of the cases it won't make any difference if you compile 
  683. ; with DOS=2.... major dos version number (2, 3 or 4)
  684.              DOS      EQU 3
  685.  
  686. ; parameter block to interface for int 30H (call86 & VM86CALL)
  687. VM86BLK      STRUC
  688. VMSEGFLAG    DD       0            ; restore segment registers (flag)
  689. VMINT        DD       0            ; interrupt number
  690. VMFLAGS      DD       0            ; EFLAGS
  691. VMESP        DD       0            ; ESP
  692. VMSS         DD       0            ; SS
  693. VMES         DD       0            ; ES
  694. VMDS         DD       0            ; DS
  695. VMFS         DD       0            ; FS
  696. VMGS         DD       0            ; GS
  697. VMEBP        DD       0            ; EBP
  698. VMEBX        DD       0            ; EBX
  699. VM86BLK      ENDS
  700.  
  701. ; Access rights equates. Use these with make_desc or make_seg
  702. RO_DATA      EQU      90H          ; r/o data
  703. RW_DATA      EQU      92H          ; r/w data
  704. RO_STK       EQU      94H          ; r/o stack
  705. RW_STK       EQU      96H          ; r/w stack
  706. EX_CODE      EQU      98H          ; exec only code
  707. ER_CODE      EQU      9AH          ; read/exec code
  708. CN_CODE      EQU      9CH          ; exec only conforming code
  709. CR_CODE      EQU      9EH          ; read/exec conforming code
  710. LDT_DESC     EQU      82H          ; LDT entry
  711. TSS_DESC     EQU      89H          ; TSS entry
  712.  
  713. ; use these with make_gate
  714. CALL_GATE    EQU      8CH          ; call gate
  715. TRAP_GATE    EQU      8FH          ; trap gate
  716. INTR_GATE    EQU      8EH          ; int gate
  717. TASK_GATE    EQU      85H          ; task gate
  718.  
  719. ; dpl equates
  720. DPL0         EQU      0
  721. DPL1         EQU      20H
  722. DPL2         EQU      40H
  723. DPL3         EQU      60H
  724.  
  725. ; macro definitons
  726.  
  727. ; other macros use this to error check parameters  
  728. ; Give an error if last is blank or toomany is not blank
  729. ERRCHK       MACRO    LAST,TOOMANY
  730. IFNB         <TOOMANY>
  731. IF2
  732.              %OUT     Too many parameters
  733. ENDIF
  734.              .ERR
  735. ENDIF
  736. IFB          <LAST>
  737. IF2
  738.              %OUT     Not enough parameters
  739. ENDIF
  740.              .ERR
  741. ENDIF
  742.              ENDM
  743.  
  744. ; Perform absolute 16 bit jump (in a 16 bit segment)
  745. JMPABS       MACRO    A,B,ERRCK
  746.              ERRCHK   B,ERRCK
  747.              DB       0EAH         ; ; absoulte 16 bit jump
  748.              DW       OFFSET B
  749.              DW       A
  750.              ENDM
  751.  
  752. ; Peform absolute 32 bit jump (in a 32 bit segment)
  753. JMPABS32     MACRO    A,B,ERRCK
  754.              ERRCHK   B,ERRCK
  755.              DB       0EAH         ; ; absolute 32 bit jump
  756.              DD       OFFSET B
  757.              DW       A
  758.              ENDM
  759. ; this generates a correct 32 bit offset for a proc call
  760. ; since MASM doesn't sign extend 32 bit relative items
  761. CALL32S      MACRO    LBL,ERRCK    ; ; short call
  762.              ERRCHK   LBL,ERRCK
  763.              DB       0E8H
  764.              DD       LBL-($+4)
  765.              ENDM
  766.  
  767. CALL32F      MACRO    SG,LBL,ERRCK ; ; far call
  768.              ERRCHK   LBL,ERRCK
  769.              DB       9AH
  770.              DD       OFFSET LBL
  771.              DW       SG
  772.              ENDM
  773.  
  774. JMP32S       MACRO    LBL,ERRCK    ; ; short jump
  775.              ERRCHK   LBL,ERRCK
  776.              DB       0E9H
  777.              DD       LBL-($+4)
  778.              ENDM
  779.  
  780. ; jcc32 uses condition codes used in Intel literature conditional jump macro
  781. JCC32        MACRO    CONDX,LBL,ERRCK
  782.              ERRCHK   LBL,ERRCK
  783.              DB       0FH
  784. IFIDNI       <CONDX>,<A>
  785.              DB       87H
  786. ELSEIFIDNI   <CONDX>,<NBE>
  787.              DB       87H
  788. ELSEIFIDNI   <CONDX>, <AE>
  789.              DB       83H
  790. ELSEIFIDNI   <CONDX>, <C>
  791.              DB       82H
  792. ELSEIFIDNI   <CONDX>, <NAE>
  793.              DB       82H
  794. ELSEIFIDNI   <CONDX>, <B>
  795.              DB       82H
  796. ELSEIFIDNI   <CONDX>, <BE>
  797.              DB       86H
  798. ELSEIFIDNI   <CONDX>, <E>
  799.              DB       84H
  800. ELSEIFIDNI   <CONDX>, <Z>
  801.              DB       84H
  802. ELSEIFIDNI   <CONDX>, <G>
  803.              DB       8FH
  804. ELSEIFIDNI   <CONDX>, <GE>
  805.              DB       8DH
  806. ELSEIFIDNI   <CONDX>, <L>
  807.              DB       8CH
  808. ELSEIFIDNI   <CONDX>, <LE>
  809.              DB       8EH
  810. ELSEIFIDNI   <CONDX>, <NA>
  811.              DB       86H
  812. ELSEIFIDNI   <CONDX>, <NB>
  813.              DB       83H
  814. ELSEIFIDNI   <CONDX>, <NC>
  815.              DB       83H
  816. ELSEIFIDNI   <CONDX>, <NGE>
  817.              DB       8CH
  818. ELSEIFIDNI   <CONDX>, <NL>
  819.              DB       8DH
  820. ELSEIFIDNI   <CONDX>, <NO>
  821.              DB       81H
  822. ELSEIFIDNI   <CONDX>, <NP>
  823.              DB       8BH
  824. ELSEIFIDNI   <CONDX>, <NS>
  825.              DB       89H
  826. ELSEIFIDNI   <CONDX>, <NZ>
  827.              DB       85H
  828. ELSEIFIDNI   <CONDX>, <O>
  829.              DB       80H
  830. ELSEIFIDNI   <CONDX>, <P>
  831.              DB       8AH
  832. ELSEIFIDNI   <CONDX>, <PE>
  833.              DB       8AH
  834. ELSEIFIDNI   <CONDX>, <PO>
  835.              DB       8BH
  836. ELSEIFIDNI   <CONDX>, <S>
  837.              DB       88H
  838. ELSE
  839.              %OUT     JCC32: Unknown condition code
  840.              .ERR
  841. ENDIF
  842.              DD       LBL-($+4)
  843.              ENDM
  844.  
  845. ; Override default operand size
  846. OPSIZ        MACRO    NOPARM       ; ; op size overide
  847.              ERRCHK   X,NOPARM
  848.              DB       66H
  849.              ENDM
  850. ; Override default address size
  851. ADSIZ        MACRO    NOPARM       ; ; address size overide
  852.              ERRCHK   X,NOPARM
  853.              DB       67H
  854.              ENDM
  855. ; delay macro for interrupt controller access
  856. IDELAY       MACRO    NOPARM
  857.              LOCAL    DELAY1,DELAY2
  858.              ERRCHK   X,NOPARM
  859.              JMP      SHORT DELAY1
  860. DELAY1:      JMP      SHORT DELAY2
  861. DELAY2:
  862.              ENDM
  863.  
  864. ; BREAKPOINT MACROS
  865.  
  866. ; MACRO to turn on NBREAKPOINTS. If used with no arguments (or a 1), this 
  867. ; macro makes NBREAKPOINT active if used with an argument > 1, NBREAKPOINT 
  868. ; will break after that many passes
  869. BREAKON      MACRO    ARG,ERRCK
  870.              ERRCHK   X,ERRCK
  871.              PUSH     DS
  872.              PUSH     SEL_DATA
  873.              POP      DS
  874.              PUSH     EAX
  875.              IFB      <ARG>
  876.              MOV      AL,1
  877.              ELSE
  878.              MOV      AL,&ARG
  879.              ENDIF
  880.              MOV      BPON,AL
  881.              POP      EAX
  882.              POP      DS
  883.              ENDM
  884. ; Turns off NBREAKPOINT
  885. BREAKOFF     MACRO    NOPARAM
  886.              ERRCHK   X,NOPARAM
  887.              PUSH     DS
  888.              PUSH     SEL_DATA
  889.              POP      DS
  890.              PUSH     EAX
  891.              XOR      AL,AL
  892.              MOV      BPON,AL
  893.              POP      EAX
  894.              POP      DS
  895.              ENDM
  896. BREAKPOINT   MACRO    NOPARM
  897.              ERRCHK   X,NOPARM
  898.              INT      3
  899.              ENDM
  900. ; Counter breakpoint - use BREAKON to set count control
  901.  
  902. ; BREAKPOINT with memory dump. 
  903. ; usage: BREAKDUMP seg_selector, offset, number_of_words
  904. BREAKDUMP    MACRO    SEG,OFF,CNT,ERRCK
  905.              ERRCHK   CNT,ERRCK
  906.              PUSH     EAX
  907.              PUSH     DS
  908.              MOV      AX,SEL_DATA
  909.              MOV      DS,AX
  910.              MOV      AX,&SEG
  911.              MOV      DUMP_SEG,AX
  912.              MOV      EAX,OFFSET &OFF
  913.              MOV      DUMP_OFF,EAX
  914.              MOV      EAX,&CNT
  915.              MOV      DUMP_CNT,EAX
  916.              POP      DS
  917.              POP      EAX
  918.              BREAKPOINT
  919.              ENDM
  920. NBREAKDUMP   MACRO    SEG,OFF,CNT,ERRCK
  921.              ERRCHK   CNT,ERRCK
  922.              LOCAL    NONBP
  923.              PUSH     DS
  924.              PUSH     SEL_DATA
  925.              POP      DS
  926.              PUSHFD
  927.              OR       BPON,0
  928.              JZ       NONBP
  929.              DEC      BPON
  930.              JNZ      NONBP
  931.              POPFD
  932.              POP      DS
  933.              BREAKDUMP SEG,OFF,CNT
  934. NONBP:
  935.              POPFD
  936.              POP      DS
  937.              ENDM
  938.  
  939. ; determine linear address of first free byte of memory (to nearest paragraph)
  940. LOADFREE     MACRO    REG,ERRCK
  941.              ERRCHK   REG,ERRCK
  942.              XOR      E®,E®
  943.              MOV      ®,SEG ZZZGROUP
  944.              SHL      E®,4
  945.              ENDM
  946.  
  947. ; Set up PINTFRAME  (uses eax). Loads vmstack & vmdata to the ss:esp and 
  948. ; ds slots in pintframe  -- default ss:esp=ssint1 -- default ds=userdata
  949. PROT_STARTUP MACRO    VMSTACK,VMDATA,ERRCK
  950.              ERRCHK   X,ERRCK
  951. IFB          <VMSTACK>
  952.              MOV      AX,SEG SSINT1
  953. ELSE
  954.              MOV      AX,SEG VMSTACK
  955. ENDIF
  956.              MOV      PINTFRAME.VMSS,EAX
  957. IFB          <VMSTACK>
  958.              MOV      EAX, OFFSET SSINT1
  959. ELSE
  960.              MOV      EAX, OFFSET VMSTACK
  961. ENDIF
  962.              MOV      PINTFRAME.VMESP,EAX
  963. IFB          <VMDATA>
  964.              MOV      AX,SEG USERDATA
  965. ELSE
  966.              MOV      AX,SEG VMDATA
  967. ENDIF
  968.              MOV      PINTFRAME.VMDS,EAX
  969.              ENDM
  970.  
  971. ; start PROT user segments
  972. PROT_CODE    MACRO    NOPARM
  973.              ERRCHK   X,NOPARM
  974. USERCODE     SEGMENT  PARA PUBLIC 'CODE32' USE32
  975. USERCODEBEG  EQU      $
  976.              ASSUME   CS:USERCODE, DS:USERDATA, ES:DAT32
  977.              ENDM
  978.  
  979. PROT_DATA    MACRO    NOPARM
  980.              ERRCHK   X,NOPARM
  981. USERDATA     SEGMENT  PARA PUBLIC 'DATA32' USE32
  982. USERDATABEG  EQU      $
  983.              ENDM
  984.  
  985. PROT_CODE_END MACRO   NOPARM
  986.              ERRCHK   X,NOPARM
  987. USERCODEEND  EQU      $
  988. USERCODE     ENDS
  989.              ENDM
  990.  
  991. PROT_DATA_END MACRO   NOPARM
  992.              ERRCHK   X,NOPARM
  993. USERDATAEND  EQU      $
  994. USERDATA     ENDS
  995.              ENDM
  996.  
  997. ; Simplfy programs with no data segment
  998. NODATA       MACRO    NOPARM
  999.              ERRCHK   X,NOPARM
  1000.              PROT_DATA
  1001.              PROT_DATA_END
  1002.              ENDM
  1003.  
  1004. ; Mnemonic for call86 call
  1005. VM86CALL     MACRO    NOPARM
  1006.              ERRCHK   X,NOPARM
  1007.              CALL32F  SEL_CODE32,CALL86
  1008.              ENDM
  1009.  
  1010. ; Mnemonic for dos return
  1011. BACK2DOS     MACRO    RC,ERRCK
  1012.              ERRCHK   X,ERRCK
  1013. IFNB         <RC>
  1014.              MOV      AL,RC
  1015. ENDIF
  1016.              JMPABS32 SEL_CODE16,BACK16
  1017.              ENDM
  1018.  
  1019. ; Variables and macro to create GDT/LDT/IDT entries
  1020. C_GDT        =        0
  1021. C_LDT        =        0
  1022. C_IDT        =        0
  1023.  
  1024. ; create "next" descriptor with name in table. If no table specified, use GDT
  1025. DESC         MACRO    NAME,TABLE,ERRCK
  1026.              DQ       0
  1027. IFB          <TABLE>
  1028.              NAME     = C_GDT
  1029. C_GDT        =        C_GDT+8
  1030. ELSE
  1031. IFIDNI       <TABLE>,<LDT>
  1032. ; For LDT selectors, set the TI bit to one
  1033.              NAME     = C_&TABLE OR 4
  1034. ELSE
  1035.              NAME     = C_&TABLE
  1036. ENDIF
  1037. C_&TABLE     =        C_&TABLE+8
  1038. ENDIF
  1039.              ENDM
  1040.  
  1041.  
  1042. [LISTING FOUR]
  1043.  
  1044. ;********************************************************************
  1045. ;*                                                                  *
  1046. ;* PROT - A 386 protected mode DOS extender                         *
  1047. ;* Copyright (C) 1989, by Al Williams                               *
  1048. ;* All rights reserved.                                             *
  1049. ;*                                                                  *
  1050. ;* Permission is granted for non-commercial use of this software    *
  1051. ;* subject to certain conditions (see PROT.ASM).                    *
  1052. ;*                                                                  *
  1053. ;* This file is: STACKS.INC, which contains all the stack segments. *
  1054. ;*                                                                  *
  1055. ;********************************************************************
  1056. ; 16 bit stack segment (for CODE16)
  1057. SSEG         SEGMENT  PARA STACK 'STACK' USE16
  1058. SSEG0        DB       DOSSTACK DUP (?)
  1059. SSEG1        EQU      $
  1060. SSEG         ENDS
  1061.  
  1062. ; 16 bit stack segment for vm86 int (both hardware & INT 30)
  1063. SSINT        SEGMENT  PARA STACK 'STACK' USE16
  1064. SSINT0       DB       VM86STACK DUP (?)
  1065. SSINT1       EQU      $
  1066. SSINT        ENDS
  1067.  
  1068. ; private stack for default critical error handler dos calls
  1069. CSTACK       SEGMENT  PARA STACK 'STACK' USE16
  1070.              DB       CRITSTACK DUP (?)
  1071. CSTACK       ENDS
  1072.  
  1073.  
  1074. ; 32 bit stack segment
  1075. SS32         SEGMENT  PARA PUBLIC 'STACK' USE32
  1076. SSEG32       DB       PMSTACK DUP (?)
  1077. SSEG321      EQU      $
  1078. SS32         ENDS
  1079.  
  1080.  
  1081. [LISTING FIVE]
  1082.  
  1083. ;********************************************************************
  1084. ;*                                                                  *
  1085. ;* PROT - A 386 protected mode DOS extender                         *
  1086. ;* Copyright (C) 1989, by Al Williams                               *
  1087. ;* All rights reserved.                                             *
  1088. ;*                                                                  *
  1089. ;* Permission is granted for non-commercial use of this software    *
  1090. ;* subject to certain conditions (see PROT.ASM).                    *
  1091. ;*                                                                  *
  1092. ;* This file is: INT386.INC                                         *
  1093. ;*                                                                  *
  1094. ;********************************************************************
  1095.  
  1096. ; Peculiarities
  1097. ; 1 - We don't emulate lock, IRETD, PUSHFD, POPFD yet
  1098. ; 2 - When calling INT 25 or INT 26 from protected mode
  1099. ;     flags are destroyed (not left on stack as in VM86, real mode)
  1100. ; 3 - For now I don't support adding offsets to the return address
  1101. ;     on your vm86 stack to change where IRET goes to. That could be
  1102. ;     fixed, but I don't know of any PC software that does that
  1103.  
  1104.  
  1105. ; fake segment for far ret interrupts
  1106. ; (this segment has no descriptor in GDT/LDT)
  1107. QISR         SEGMENT  PARA PUBLIC 'CODE16' USE16
  1108.              ASSUME   CS:QISR
  1109. ; push sacrifical words for IRET to eat.
  1110. ; PL0 stack controls return anyway
  1111. QIRET:
  1112.              PUSH     0
  1113.              PUSH     0
  1114.              PUSH     0
  1115.              IRET
  1116. QISR         ENDS
  1117.  
  1118. ; IDT segment
  1119. IDTABLE      SEGMENT  PARA PUBLIC 'DATA32' USE32
  1120. IDTBEG       EQU      $
  1121.              DQ       TOPINT+1 DUP (0)
  1122. IDTEND       EQU      $
  1123. IDTABLE      ENDS
  1124.  
  1125.  
  1126. ;ISR segment
  1127. DEFINT       MACRO    N
  1128. INT&N        LABEL    FAR
  1129.              PUSH     &N
  1130.              JMP      NEAR PTR INTDUMP
  1131.              ENDM
  1132.  
  1133.  
  1134. ISR          SEGMENT  PARA PUBLIC 'CODE32' USE32
  1135.              ASSUME   CS:ISR
  1136. ISRBEG       EQU      $
  1137. ; This code defines interrupt handlers from 0 to TOPINT
  1138. ; (TOPINT is defined in EQUMAC.INC)
  1139. INTNO        =        0
  1140.              REPT     TOPINT+1
  1141.              DEFINT   %INTNO
  1142. INTNO        =        INTNO + 1
  1143.              ENDM
  1144.  
  1145. ; Debug dump messages
  1146. MESSAREA     DB       'INT=',0
  1147. STKM         DB       'Stack Dump:',0
  1148. TASKM        DB       ' TR=',0
  1149. RTABLE       DB       'G'
  1150.              DB       'F'
  1151.              DB       'D'
  1152.              DB       'E'
  1153. GTABLE       DB       'DISIBPSPBXDXCXAX'
  1154. MEMMESS      DB       'Memory Dump:',0
  1155.  
  1156. ; All interrupts come here
  1157. ; We check for the interrupt # pushed on the stack and
  1158. ; vector accordingly. This adds some interrupt latency,
  1159. ; but simplifies IDT construction.
  1160. INTDUMP      LABEL    NEAR
  1161. ; check for GP error
  1162.              CMP      BYTE PTR [ESP],0DH
  1163.              JZ       NEAR PTR INT13H
  1164. NOT13:
  1165. ; check for vm86 psuedo-int
  1166.              CMP      BYTE PTR [ESP],30H
  1167.              JZ       NEAR PTR INT30H
  1168. ; hardware interrupt?
  1169.              CMP      BYTE PTR [ESP],20H
  1170.              JB       SHORT NOTIO
  1171. IF           ATCLASS
  1172.              CMP      BYTE PTR [ESP],2FH
  1173. ELSE
  1174.              CMP      BYTE PTR [ESP],27H
  1175. ENDIF
  1176.              JA       SHORT NOTIO
  1177.              JMP      NEAR PTR HWINT
  1178. NOTIO:
  1179. ; if we made it here, we have an unexpected interrupt
  1180. ; so crank out a debug dump and exit to dos
  1181.              PUSHAD
  1182.              PUSH     GS
  1183.              PUSH     FS
  1184.              PUSH     DS
  1185.              PUSH     ES
  1186.              MOV      AX,SEL_VIDEO
  1187.              MOV      ES,AX
  1188.              MOV      AX,CS
  1189.              MOV      DS,AX
  1190. ; do dump
  1191.              MOV      ECX,4
  1192. INTL1:
  1193.              MOV      AL,[RTABLE-1+ECX]
  1194.              CALL32F  SEL_CODE32,OUCH
  1195.              MOV      AL,'S'
  1196.              CALL32F  SEL_CODE32,OUCH
  1197.              MOV      AL,'='
  1198.              CALL32F  SEL_CODE32,OUCH
  1199.              POP      EAX
  1200.              CALL32F  SEL_CODE32,HEXOUT2
  1201.              PUSH     ECX
  1202.              MOV      ECX,6
  1203. LSP1:        MOV      AL,' '
  1204.              CALL32F  SEL_CODE32,OUCH
  1205.              LOOP     LSP1
  1206.              POP      ECX
  1207.              LOOP     INTL1
  1208.              CALL32F  SEL_CODE32,CRLF
  1209.              XOR      ECX,ECX
  1210. INTL2:       CMP      CL,5
  1211.              JNZ      SHORT NOCRINT
  1212.              CALL32F  SEL_CODE32,CRLF
  1213. NOCRINT:
  1214.              MOV      AL,'E'
  1215.              CALL32F  SEL_CODE32,OUCH
  1216.              MOV      AL,[GTABLE+ECX*2]
  1217.              CALL32F  SEL_CODE32,OUCH
  1218.              MOV      AL,[GTABLE+1+ECX*2]
  1219.              CALL32F  SEL_CODE32,OUCH
  1220.              MOV      AL,'='
  1221.              CALL32F  SEL_CODE32,OUCH
  1222.              POP      EAX
  1223.              CALL32F  SEL_CODE32,HEXOUT4
  1224.              MOV      AL,' '
  1225.              CALL32F  SEL_CODE32,OUCH
  1226.              INC      CL
  1227.              CMP      CL,8
  1228.              JNE      SHORT INTL2
  1229.              MOV      EBX,OFFSET MESSAREA
  1230.              CALL32F  SEL_CODE32,MESSOUT
  1231.              POP      EAX
  1232.              CALL32F  SEL_CODE32,HEXOUT
  1233.              MOV      EBX,OFFSET TASKM
  1234.              CALL32F  SEL_CODE32,MESSOUT
  1235.              STR      AX
  1236.              CALL32F  SEL_CODE32,HEXOUT2
  1237.              CALL32F  SEL_CODE32,CRLF
  1238.  
  1239. ; stack dump
  1240.              XOR      EAX,EAX
  1241.              MOV      AX,SS
  1242.              LSL      EDX,EAX
  1243.              JNZ      SHORT INTABT
  1244.              MOV      EBX,OFFSET STKM
  1245.              CALL32F  SEL_CODE32,MESSOUT
  1246.              XOR      CL,CL
  1247. INTL3:       CMP      ESP,EDX
  1248.              JAE      SHORT INTABT
  1249.              TEST     CL,7
  1250.              JNZ      SHORT NOSCR
  1251.              CALL32F  SEL_CODE32,CRLF
  1252. NOSCR:       POP      EAX
  1253.              CALL32F  SEL_CODE32,HEXOUT4
  1254.              INC      CL
  1255.              MOV      AL,' '
  1256.              CALL32F  SEL_CODE32,OUCH
  1257.              JMP      SHORT INTL3
  1258.  
  1259. INTABT:
  1260. ; Check for memory dump request
  1261.              MOV      AX,SEL_DATA
  1262.              MOV      DS,AX
  1263.              ASSUME   DS:DAT32
  1264.              MOV      AX,WORD PTR DUMP_SEG
  1265.              OR       AX,AX
  1266.              JZ       SHORT NOMEMDUMP
  1267. ; come here to do memory dump
  1268.              CALL32F  SEL_CODE32,CRLF
  1269.              PUSH     DS
  1270.              PUSH     CS
  1271.              POP      DS
  1272.              MOV      EBX,OFFSET MEMMESS
  1273.              CALL32F  SEL_CODE32,MESSOUT
  1274.              CALL32F  SEL_CODE32,CRLF
  1275.              POP      DS
  1276.              MOV      AX,WORD PTR DUMP_SEG
  1277.              MOV      ES,AX
  1278.              CALL32F  SEL_CODE32,HEXOUT2
  1279.              MOV      AL,':'
  1280.              CALL32F  SEL_CODE32,OUCH
  1281.              MOV      EDX,DUMP_OFF
  1282.              MOV      EAX,EDX
  1283.              CALL32F  SEL_CODE32,HEXOUT4
  1284.              MOV      ECX,DUMP_CNT
  1285. DUMPLOOP:
  1286.              MOV      AL,' '
  1287.              CALL32F  SEL_CODE32,OUCH
  1288.              MOV      EAX,ES:[EDX] ; get word
  1289.              CALL32F  SEL_CODE32,HEXOUT4
  1290.              ADD      EDX,4
  1291.              SUB      ECX,4
  1292.              JA       SHORT DUMPLOOP
  1293.              CALL32F  SEL_CODE32,CRLF
  1294. NOMEMDUMP:
  1295.  
  1296.  
  1297.              MOV      AL,20H       ; Send EOI signal
  1298. IF           ATCLASS
  1299.              OUT      0A0H,AL
  1300. ENDIF
  1301.              OUT      20H,AL       ; just in case hardware did it
  1302.              MOV      AL,7FH       ; return 7f to DOS
  1303.              BACK2DOS
  1304.  
  1305. ; Here we check the GP fault
  1306. ; if the mode isn't VM86 we do a debug dump
  1307. ; Otherwise we try and emulate an instruction
  1308. ; If the instruction isn't known, we do a debug dump
  1309. INT13H:
  1310.              ADD      ESP,4        ; balance stack (remove intno)
  1311.              TEST     [ESP+12],20000H
  1312.              JZ       SHORT SIM13A ; wasn't a vm86 interrupt!
  1313.              ADD      ESP,4        ; remove error code
  1314.              PUSH     EAX
  1315.              PUSH     EBX
  1316.              PUSH     DS
  1317.              PUSH     EBP
  1318.              MOV      EBP,ESP      ; point to stack frame
  1319.              ADD      EBP,10H
  1320.              MOV      AX,SEL_DATA0
  1321.              MOV      DS,AX
  1322.              MOV      EBX,[EBP+4]  ; get cs
  1323.              AND      EBX,0FFFFH
  1324.              SHL      EBX,4
  1325.              ADD      EBX,[EBP]    ; get eip
  1326.              XOR      EAX,EAX      ; al = OPCODE byte
  1327.                                    ; ah = # of bytes skipped over
  1328.                                    ; bit 31 of eax=1 if OPSIZ prefix
  1329.                                    ; encountered
  1330.              JMP      SHORT INLOOP
  1331.  
  1332. ; set sign bit of eax if OPSIZ
  1333. FSET:        OR       EAX,80000000H
  1334. INLOOP:      MOV      AL,[EBX]
  1335.              INC      AH
  1336.              INC      EBX
  1337.              CMP      AL,66H       ; opsize prefix
  1338.              JZ       SHORT FSET
  1339. ; scan for instructions
  1340.              CMP      AL,9DH
  1341.              JZ       SHORT DOPOPF
  1342.              CMP      AL,9CH
  1343.              JZ       SHORT DOPUSHF
  1344.              CMP      AL,0FAH
  1345.              JZ       NEAR PTR DOCLI
  1346.              CMP      AL,0FBH
  1347.              JZ       NEAR PTR DOSTI
  1348.              CMP      AL,0CDH
  1349.              JZ       NEAR PTR DOINTNN
  1350.              CMP      AL,0CFH
  1351.              JZ       NEAR PTR DOIRET
  1352.              CMP      AL,0F0H
  1353.              JZ       NEAR PTR DOLOCK
  1354. ; Whoops! What the $#$%$#! is that?
  1355.              POP      EBP
  1356.              POP      DS
  1357.              POP      EBX
  1358.              POP      EAX
  1359. SIM13:
  1360.              PUSH     0            ; simulate error
  1361. SIM13A:
  1362.              PUSH     13           ; simulate errno
  1363.              JMP32S   NOT13
  1364.  
  1365. ;********************************************************************
  1366. ; The following routines emulate VM86 instructions. Their conditions
  1367. ; on entry are:
  1368. ; eax[31]=1 iff opsiz preceeded instruction
  1369. ; ah=count to adjust eip on stack
  1370. ; al=instruction
  1371. ; [EBX] next opcode byte
  1372. ; ds: zerobase segment
  1373.  
  1374.  
  1375. ; This routine emulates a popf
  1376. DOPOPF:
  1377.              MOV      BX, [EBP]    ; fix IP
  1378.              ADD      BL,AH
  1379.              ADC      BH,0
  1380.              MOV      [EBP],BX
  1381. ; get ss*10H, add esp fetch top of stack
  1382.              MOVZX    EBX,WORD PTR [EBP+10H]
  1383.              SHL      EBX,4
  1384.              ADD      EBX,[EBP+0CH]
  1385.              MOVZX    EAX,WORD PTR [EBX]
  1386.              MOV      EBX,[EBP+8]  ; get his real flags
  1387.              AND      BX,07000H    ; only preserve NT,IOPL
  1388.              AND      AX,08FFFH    ; wipe NT,IOPL in new flags
  1389.              OR       EAX,EBX
  1390.              MOV      [EBP+8],EAX  ; save his real flag image
  1391.              MOV      EBX,2
  1392.              ADD      [EBP+0CH],EBX
  1393.              MOV      EBX,0FFFEFFFFH
  1394.              AND      [EBP+8],EBX
  1395.              POP      EBP
  1396.              POP      DS
  1397.              POP      EBX
  1398.              POP      EAX
  1399.              IRETD
  1400.  
  1401. ; Routine to emulate pushf
  1402. DOPUSHF:
  1403.              MOV      BX, [EBP]    ; Fix ip
  1404.              ADD      BL,AH
  1405.              ADC      BH,0
  1406.              MOV      [EBP],BX
  1407.              MOV      EAX,[EBP+8]  ; get his flags
  1408. ; get ss, add esp and "push" flags
  1409.              MOVZX    EBX,WORD PTR [EBP+10H]
  1410.              SHL      EBX,4
  1411.              ADD      EBX,[EBP+0CH]
  1412.              MOV      [EBX-2],AX
  1413.              MOV      EBX,2
  1414. ; adjust stack
  1415.              SUB      [EBP+0CH],EBX
  1416. ; mask out flag bits
  1417.              MOV      EBX,0FFFEFFFFH
  1418.              AND      [EBP+8],EBX
  1419.              POP      EBP
  1420.              POP      DS
  1421.              POP      EBX
  1422.              POP      EAX
  1423.              IRETD
  1424.  
  1425. ; Emulate CLI
  1426. DOCLI:
  1427.              MOV      BX, [EBP]    ; Fix ip
  1428.              ADD      BL,AH
  1429.              ADC      BH,0
  1430.              MOV      [EBP],BX
  1431.              MOV      EAX,[EBP+8]  ; get flags
  1432.              OR       EAX,20000H   ; set vm, clr RF & IOPL
  1433.              AND      EAX,0FFFECDFFH
  1434.              MOV      [EBP+8],EAX  ; replace flags
  1435.              POP      EBP
  1436.              POP      DS
  1437.              POP      EBX
  1438.              POP      EAX
  1439.              IRETD
  1440.  
  1441. ; Emulate STI
  1442. DOSTI:
  1443.              MOV      BX, [EBP]    ; Fix ip
  1444.              ADD      BL,AH
  1445.              ADC      BH,0
  1446.              MOV      [EBP],BX
  1447.              MOV      EAX,[EBP+8]  ; get flags
  1448.              OR       EAX,20200H   ; set vm, clr RF & IOPL
  1449.              AND      EAX,0FFFECFFFH
  1450.              MOV      [EBP+8],EAX  ; replace flags
  1451.              POP      EBP
  1452.              POP      DS
  1453.              POP      EBX
  1454.              POP      EAX
  1455.              IRETD
  1456.  
  1457.  
  1458. ; This routine emulates an INT nn instruction
  1459. DOINTNN:
  1460.              PUSH     EDX
  1461.              PUSH     ECX
  1462. ; get ss
  1463.              MOVZX    EDX,WORD PTR [EBP+10H]
  1464.              SHL      EDX,4
  1465. ; add esp
  1466.              ADD      EDX,[EBP+0CH]
  1467. ; move flags, qsir address to vm86 stack & correct esp
  1468. ; ... flags
  1469.              MOV      CX, [EBP+08H]
  1470.              MOV      [EDX-2],CX
  1471.              MOV      WORD PTR [EDX-4],SEG QIRET
  1472.              MOV      WORD PTR [EDX-6],OFFSET QIRET
  1473.              SUB      DWORD PTR [EBP+0CH],6
  1474.              MOV      CX, [EBP]    ; ip
  1475.              INC      AH           ; adjust ip by # of bytes to skip
  1476.              ADD      CL,AH
  1477.              ADC      CH,0
  1478.              MOV      [EBP],CX
  1479. ; get tss alias (always directly above TSS in GDT)
  1480.              STR      DX           ; get our task #
  1481.              SUB      DX,8         ; alias is one above
  1482.              MOV      ES,DX
  1483.              MOV      DX,SEL_DATA
  1484.              MOV      DS,DX
  1485.              ASSUME   DS:DAT32
  1486. ; get pl0 esp from TSS & push to local stack
  1487.              MOV      EDX,INTSP
  1488.              SUB      EDX,4
  1489.              MOV      INTSP,EDX
  1490.              MOV      ECX,ES:[4]   ; esp0
  1491.              MOV      [EDX],ECX
  1492. ; get int vector
  1493.              MOV      DX,SEL_DATA0
  1494.              MOV      DS,DX
  1495.              MOV      ECX,ESP      ; adjust stack for int 30H
  1496.              ADD      ECX,60
  1497.              MOV      ES:[4],ECX
  1498. ; test for zero; if so called from int 30H
  1499.              OR       AH,AH
  1500.              MOVZX    EDX,AL
  1501.              JZ       SHORT FROM30
  1502. ; otherwise get int vector from CS:EIP stream
  1503.              MOVZX    EDX,BYTE PTR [EBX]
  1504.              MOV      ECX,ESP
  1505.              ADD      ECX,24
  1506.              MOV      ES:[4],ECX   ; adjust stack for non-int 30H
  1507. FROM30:
  1508. ; interrupt vector*4 = VM86 interrupt vector address
  1509.              SHL      EDX,2
  1510. ; try to clean up mess on stack
  1511.              MOV      AX,SEL_DATA
  1512.              MOV      DS,AX
  1513.              MOV      STO2,EDX
  1514.              POP      ECX
  1515.              POP      EDX
  1516.              XCHG     STO2,EDX
  1517.              MOV      STO1,ECX
  1518.              MOV      STO3,EBP
  1519.              POP      EBP
  1520.              XCHG     STO3,EBP
  1521.              POP      ECX
  1522.              MOV      BX,SEL_DATA
  1523.              MOV      DS,BX
  1524.              MOV      STO4,ECX
  1525.              POP      EBX
  1526.              POP      EAX
  1527.              MOV      CX,SEL_DATA0
  1528.              MOV      DS,CX
  1529. ; copy segment registers & esp for vm86 int
  1530.              PUSH     [EBP+20H]
  1531.              PUSH     [EBP+1CH]
  1532.              PUSH     [EBP+18H]
  1533.              PUSH     [EBP+14H]
  1534.              PUSH     [EBP+10H]
  1535.              PUSH     [EBP+0CH]
  1536.              MOV      ECX,[EBP+08]
  1537. ; push flags (with vm=1,iopl=0),cs, eip, rf=0
  1538.              OR       ECX,20000H
  1539. ; clear iopl, rf, tf, if and push flags
  1540.              AND      ECX,0FFFECCFFH
  1541.              PUSH     ECX
  1542. ; read new cs/ip from 8086 idt
  1543. ; ... push CS
  1544.              MOVZX    ECX,WORD PTR [EDX+2]
  1545.              PUSH     ECX
  1546. ; ... push IP
  1547.              MOVZX    ECX,WORD PTR [EDX]
  1548.              PUSH     ECX
  1549.              MOV      CX,SEL_DATA
  1550.              MOV      DS,CX
  1551.              PUSH     STO4
  1552.              MOV      ECX,STO1
  1553.              MOV      EDX,STO2
  1554.              MOV      EBP,STO3
  1555.              POP      DS
  1556.              IRETD                 ; go on to vm86 land
  1557.  
  1558. ; Emulate IRET instruction
  1559. DOIRET:
  1560. ; vm86 stack
  1561.              MOVZX    EAX,WORD PTR[EBP+10H]
  1562.              SHL      EAX,4
  1563.              ADD      EAX,[EBP+0CH]
  1564.              MOV      EBX,[EAX]    ; get cs:ip
  1565. ; If top of stack=0:0 than a RETF or RETF 2 was detected
  1566.              OR       EBX,EBX
  1567.              JZ       SHORT FARRETINT
  1568.              PUSH     ECX
  1569.              XOR      ECX,ECX
  1570. ; compare return address with QIRET
  1571.              MOV      CX, SEG QIRET
  1572.              SHL      ECX,16
  1573.              MOV      CX,OFFSET QIRET
  1574.              CMP      EBX,ECX
  1575.              POP      ECX
  1576. ; if equal than "normal" IRET
  1577.              JZ       SHORT NORMIRET
  1578.  
  1579. ; Not equal then that vm86 jerk is "faking" an IRET to pass control
  1580. ; We must build a "fake" pl0 frame
  1581. ; adjust sp
  1582.              ADD      DWORD PTR [EBP+0CH],6
  1583. ; get ip
  1584.              MOVZX    EBX,WORD PTR [EAX]
  1585.              MOV      [EBP],EBX
  1586. ; get cs
  1587.              MOVZX    EBX,WORD PTR [EAX+2]
  1588.              MOV      [EBP+4],EBX
  1589. ; get new flags
  1590.              MOVZX    EBX,WORD PTR [EAX+4]
  1591.              OR       EBX,20000H   ; set vm, clr RF & IOPL
  1592.              AND      EBX,0FFFECFFFH
  1593.              MOV      [EBP+8],EBX
  1594.              POP      EBP
  1595.              POP      DS
  1596.              POP      EBX
  1597.              POP      EAX
  1598.              IRETD                 ; go on
  1599.  
  1600. ; this means qiret caught a FAR RET instead of an IRET
  1601. ; we must preserve our current flags!
  1602. FARRETINT:
  1603.              MOV      EAX,EBP
  1604.              POP      EBP
  1605.              POP      DS
  1606.              PUSH     EBP
  1607.              PUSH     EAX
  1608.              MOV      BX,DS
  1609.              MOV      AX,SEL_DATA
  1610.              MOV      DS,AX
  1611.              MOV      STO3,EBX
  1612.              POP      EBP          ; ISR's ebp
  1613.              MOV      EAX,[EBP+0CH]
  1614.              ADD      EAX,6        ; skip pushes from qiret
  1615.              MOV      STO4,EAX
  1616. ; get flags
  1617.              MOV      EAX,[EBP+08H]
  1618.              MOV      STO2,EAX
  1619.              JMP      SHORT NIRET
  1620.  
  1621. ; This handles the "normal" case
  1622. NORMIRET:
  1623.              MOV      BX,[EAX+4]   ; get flags
  1624.              MOV      EAX,EBP
  1625.              POP      EBP
  1626.              POP      DS
  1627.              PUSH     EBP
  1628.              PUSH     EAX
  1629.              MOV      AX,BX
  1630.              MOV      BX,DS
  1631.              PUSH     SEL_DATA
  1632.              POP      DS
  1633.              MOV      STO2,EAX
  1634.              MOV      STO3,EBX
  1635.              POP      EBP          ; ISR's ebp
  1636.              XOR      EAX,EAX
  1637.              MOV      STO4,EAX
  1638. NIRET:
  1639.              PUSH     ESI
  1640.              XOR      ESI,ESI
  1641.              OR       DWORD PTR [EBP+28H],0
  1642. ; if CS=0 then int 30H asked  for segment save
  1643.              JNZ      SHORT V86IRET
  1644.              MOV      EAX,[EBP+14H]
  1645.              MOV      SAV_ES,EAX
  1646.              MOV      EAX,[EBP+18H]
  1647.              MOV      SAV_DS,EAX
  1648.              MOV      EAX,[EBP+1CH]
  1649.              MOV      SAV_FS,EAX
  1650.              MOV      EAX,[EBP+20H]
  1651.              MOV      SAV_GS,EAX
  1652.              MOV      ESI,8
  1653.  
  1654. V86IRET:
  1655.              MOV      AX,ES
  1656.              MOV      STO1,EAX
  1657.              POP      EBP
  1658.              XCHG     EBP,[ESP]
  1659. ; get tss alias
  1660.              STR      AX
  1661.              SUB      AX,8
  1662.              MOV      ES,AX
  1663.              ASSUME   DS:DAT32
  1664.              MOV      EAX,ES:[4]   ; get our current stack begin
  1665. ; see if we have to balance the VM86 stack
  1666.              TEST     SS:[EAX+ESI+8],20000H
  1667.              JZ       SHORT STKADJD
  1668.              MOV      EBX,STO4
  1669.              OR       EBX,EBX
  1670.              JZ       SHORT ADJSTK
  1671. ; balance vm86 stack
  1672.              MOV      SS:[EAX+ESI+0CH], EBX
  1673.              JMP      SHORT STKADJD
  1674. ADJSTK:      ADD      DWORD PTR SS:[EAX+ESI+0CH],6
  1675. STKADJD:
  1676. ; get quasi flags
  1677.              MOV      EBX,STO2
  1678. ; get real flags
  1679.              PUSH     SS:[EAX+ESI+8]
  1680. ; preserve flags
  1681.              MOV      DWORD PTR SS:[EAX+ESI+8],EBX
  1682. LEAVEFLAGS:
  1683. ; only let 8086 part of flags stay
  1684.              AND      DWORD PTR SS:[EAX+ESI+08],01FFFH
  1685.              POP      EBX          ; load real flags into ebx
  1686. ; save 386 portion of old flags (AND IP)
  1687.              AND      EBX,0FFFFE200H
  1688.              OR       SS:[EAX+ESI+8],EBX
  1689.              POP      ESI
  1690.              XCHG     EAX,[ESP]
  1691.              PUSH     EAX          ; stack = ebx, new sp
  1692.              MOV      EBX,INTSP
  1693. ; get prior pl0 esp from local stack
  1694.              MOV      EAX,[EBX]
  1695.              ADD      EBX,4
  1696.              MOV      INTSP,EBX
  1697.              MOV      ES:[4],EAX   ; restore to TSS
  1698. ; restore registers
  1699.              POP      EBX
  1700.              MOV      ES,WORD PTR STO1
  1701.              MOV      DS,WORD PTR STO3
  1702.              POP      EAX          ; restore "real" eax
  1703.              XCHG     EAX,[ESP]
  1704.              POP      ESP          ; set up new top stack
  1705.              XCHG     EAX,[ESP+4]
  1706.              OR       EAX,EAX      ; test cs
  1707.              XCHG     EAX,[ESP+4]
  1708.              JNZ      SHORT GOIRET
  1709.              ADD      ESP,8        ; skip fake CS/IP from INT 30H
  1710. GOIRET:
  1711. ; reset resume flag
  1712.              AND      DWORD PTR [ESP+8],0FFFECFFFH
  1713.              IRETD
  1714.  
  1715.  
  1716.  
  1717.  
  1718. ; Emulate lock prefix
  1719. DOLOCK:
  1720.  
  1721.              POP      EBP
  1722.              POP      DS
  1723.              POP      EBX
  1724.              POP      EAX
  1725.              PUSH     0FFFFH
  1726.              PUSH     13           ; simulate errno
  1727.              JMP32S   NOT13
  1728.  
  1729.  
  1730. ; This is the interface routine to allow a protected mode
  1731. ; program call VM86 interrupts.
  1732. ; Call with es:ebx pointing to a parameter block
  1733. ; +00 flag - if 1 then resave ES, DS, FS & GS
  1734. ;            into parameter block after call
  1735. ; +04 int number (0-255)   (required)
  1736. ; +08 eflags
  1737. ; +12 vm86 esp    (required)
  1738. ; +16 vm86 ss     (required)
  1739. ; +20 vm86 es
  1740. ; +24 vm86 ds
  1741. ; +28 vm86 fs
  1742. ; +32 vm86 gs
  1743. ; +36 vm86 ebp  ( to replace that used in call )
  1744. ; +40 vm86 ebx  ( to replace that used in call )
  1745. ;
  1746. ; all other registers will be passed to vm86 routine
  1747. ;
  1748. ; This routine depends on the dointnn routine
  1749.  
  1750. INT30H:
  1751.              ADD      ESP,4        ; remove intno
  1752.              CMP      BYTE PTR ES:[EBX],0
  1753.              JZ       SHORT NOSEGSAV
  1754. ; dummy CS/IP to signal IRET to save segments
  1755.              PUSH     0
  1756.              PUSH     0
  1757. NOSEGSAV:
  1758.              PUSH     ES:[EBX+32]  ; stack up registers
  1759.              PUSH     ES:[EBX+28]
  1760.              PUSH     ES:[EBX+24]
  1761.              PUSH     ES:[EBX+20]
  1762.              PUSH     ES:[EBX+16]
  1763.              PUSH     ES:[EBX+12]
  1764. ; force VM86=1 in EFLAGS
  1765.              XCHG     EAX,ES:[EBX+8]
  1766.              OR       EAX,20000H
  1767.              AND      EAX,0FFFECFFFH
  1768.              PUSH     EAX
  1769.              XCHG     EAX,ES:[EBX+8]
  1770.              PUSH     0            ; don't care cs
  1771.              PUSH     0            ; don't care eip
  1772.              MOV      EBP,ESP
  1773.              PUSH     EAX
  1774.              PUSH     ES:[EBX+40]  ; vm86 ebx
  1775.              PUSH     DS
  1776.              PUSH     ES:[EBX+36]  ; vm86 ebp
  1777.              MOV      AX,SEL_DATA0
  1778.              MOV      DS,AX
  1779. ; get user's intno
  1780.              MOV      AL,ES:[EBX+4]
  1781. ; set flag to dointnn not to check cs:ip for int #
  1782.              MOV      AH,0FFH
  1783. ; go ahead.... make my interrupt
  1784.              JMP32S   DOINTNN
  1785.  
  1786. ; handle hardware int!
  1787. ; This routine uses INT 30 to handle HW interrupts
  1788. ; If interrupted in protected mode, a special stack
  1789. ; is used. If in VM86 mode, the current VM86 stack is used
  1790. HWINT:
  1791.              XCHG     EAX,[ESP]    ; swap eax & int #
  1792.              PUSH     DS
  1793.              PUSH     ES
  1794.              PUSH     EBX
  1795.              MOV      BX,SEL_DATA
  1796.              MOV      DS,BX
  1797.              MOV      ES,BX
  1798.              CMP      EAX,28H
  1799.              JB       SHORT IRQ07
  1800.              ADD      EAX,48H      ; vector IRQ8-F to INT 70-77
  1801.              JMP      SHORT IRQSET
  1802. IRQ07:
  1803.              SUB      EAX,24       ; vector IRQ0-7 to INT 8-0F
  1804. IRQSET:
  1805. ; set up special interrupt frame
  1806.              MOV      HINTFRAME.VMINT,EAX
  1807.              MOV      HINTFRAME.VMEBP,EBP
  1808.              POP      EBX
  1809.              MOV      HINTFRAME.VMEBX,EBX
  1810.              PUSH     EBX
  1811.              MOV      EAX,020000H  ; model flags
  1812.              MOV      HINTFRAME.VMFLAGS,EAX
  1813.              MOV      EAX,OFFSET SSINT1
  1814.              MOV      HINTFRAME.VMESP,EAX
  1815.              MOV      AX,SEG SSINT1
  1816.              MOV      HINTFRAME.VMSS,EAX
  1817.              MOV      EAX,[ESP+24] ; get flags
  1818.              TEST     EAX,20000H   ; check vm
  1819.              JZ       SHORT NOTVMHW
  1820.              MOV      EAX,[ESP+28] ; get vm86's esp
  1821.              MOV      HINTFRAME.VMESP,EAX
  1822.              MOV      EAX,[ESP+32]
  1823.              MOV      HINTFRAME.VMSS,EAX
  1824. NOTVMHW:
  1825.              MOV      EBX,OFFSET HINTFRAME
  1826.              PUSH     FS
  1827.              PUSH     GS
  1828.              INT      30H          ; Do interrupt
  1829.              POP      GS
  1830.              POP      FS
  1831.              POP      EBX
  1832.              POP      ES
  1833.              POP      DS
  1834.              POP      EAX
  1835.              IRETD
  1836.  
  1837. ISREND       EQU      $
  1838. ISR          ENDS
  1839.  
  1840.  
  1841.  
  1842.  
  1843. [LISTING SIX]
  1844.  
  1845. ;********************************************************************
  1846. ;*                                                                  *
  1847. ;* PROT - A 386 protected mode DOS extender                         *
  1848. ;* Copyright (C) 1989, by Al Williams                               *
  1849. ;* All rights reserved.                                             *
  1850. ;*                                                                  *
  1851. ;* Permission is granted for non-commercial use of this software    *
  1852. ;* subject to certain conditions (see PROT.ASM).                    *
  1853. ;*                                                                  *
  1854. ;* This file is: TSS.INC, the Task State Segment definitions.       *
  1855. ;*                                                                  *
  1856. ;********************************************************************
  1857. ; define TSS structure
  1858. ; for more details refer to the Intel documentation
  1859. ; remember, the defined values are only defaults, and
  1860. ; can be changed when a value is defined
  1861. TSSBLK       STRUC
  1862. BLINK        DD       0
  1863. ESPP0        DD       OFFSET SSEG321
  1864. SSP0         DD       SEL_STACK
  1865. ESPP1        DD       0
  1866. SSP1         DD       SEL_STACK
  1867. ESPP2        DD       0
  1868. SSP2         DD       SEL_STACK
  1869. CR31         DD       0
  1870. EIP1         DD       OFFSET USER
  1871. EF1          DD       200H
  1872. EAX1         DD       0
  1873. ECX1         DD       0
  1874. EDX1         DD       0
  1875. EBX1         DD       0
  1876. ESP1         DD       OFFSET SSEG321
  1877. EBP1         DD       0
  1878. ESI1         DD       0
  1879. EDI1         DD       0
  1880. ES1          DD       SEL_DATA
  1881. CS1          DD       SEL_UCODE
  1882. SS1          DD       SEL_STACK
  1883. DS1          DD       SEL_UDATA
  1884. FS1          DD       SEL_DATA0
  1885. GS1          DD       SEL_VIDEO
  1886. LDT1         DD       0
  1887.              DW       0
  1888. IOT          DW       $+2-OFFSET BLINK
  1889. IOP          DB       8192 DUP (0)
  1890.              DB       0FFH
  1891. TSSBLK       ENDS
  1892.  
  1893.  
  1894. TSSSEG       SEGMENT  PARA PUBLIC 'DATA32' USE16
  1895.              ORG      0
  1896. ; Dummy TSS that stores the original machine state
  1897. TSS0BEG      TSSBLK   <>
  1898. TSS0END      EQU      $
  1899.  
  1900. ; TSS to run the USER task
  1901. TSS1BEG      TSSBLK   <>
  1902. TSS1END      EQU      $
  1903.  
  1904. TSSSEG       ENDS
  1905.  
  1906.  
  1907. [LISTING SEVEN]
  1908.  
  1909. ;********************************************************************
  1910. ;*                                                                  *
  1911. ;* PROT - A 386 protected mode DOS extender                         *
  1912. ;* Copyright (C) 1989, by Al Williams                               *
  1913. ;* All rights reserved.                                             *
  1914. ;*                                                                  *
  1915. ;* Permission is granted for non-commercial use of this software    *
  1916. ;* subject to certain conditions (see PROT.ASM).                    *
  1917. ;*                                                                  *
  1918. ;* This file is: CODE16.INC, the 16 bit DOS entry/exit code.        *
  1919. ;*                                                                  *
  1920. ;********************************************************************
  1921.  
  1922. CSEG         SEGMENT  PARA PUBLIC 'CODE16' USE16
  1923.              ASSUME   CS:CSEG, DS:CSEG
  1924. BEG16        EQU      $
  1925. IDTSAV       DF       0            ; space to save old real mode IDT
  1926. XZRO         DF       0            ; Zero constant for inhibiting IDT
  1927.  
  1928. TEMP         EQU      THIS FWORD   ; Space to load GDT
  1929. TLIM         DW       (GDTEND-GDT)-1
  1930. TEMD         DD       0
  1931.  
  1932. ; area to save stack pointer
  1933. SOFFSAV      DW       0
  1934. SSEGSAV      DW       0
  1935.  
  1936. ; old keyboard interrupt vector -- we have to catch reboot requests
  1937. KEYCHAIN     EQU      THIS DWORD
  1938. KEYOFF       DW       ?
  1939. KEYSEG       DW       ?
  1940.  
  1941. INTM         DB       0            ; interrupt mask - pic 1
  1942. IF           ATCLASS
  1943. INTMAT       DB       0            ; interrupt mask - pic 2 (AT ONLY)
  1944. ENDIF
  1945.  
  1946. ;psp
  1947. PSP          DW       0
  1948.  
  1949. ; error messages
  1950. NOT386M      DB       'Error: this program requires an 80386 or 80486'
  1951.              DB       ' processor.',13,10,'$'
  1952. VM86M        DB       'Error: this program will not execute '
  1953.              DB       'in VM86 mode.'
  1954.              DB       13,10,'$'
  1955.  
  1956. ; 16 bit ss/sp for return to real mode
  1957. LOAD16       DD       OFFSET SSEG1-1
  1958.              DW       SEL_RDATA
  1959.  
  1960. ;****** Begin program
  1961. ENTRY        LABEL    FAR
  1962. START        PROC     NEAR
  1963.              PUSH     CS           ; set up DS segment, save PSP
  1964.              POP      DS
  1965.              MOV      AX,ES
  1966.              MOV      PSP,AX       ; save PSP
  1967.              MOV      BX,DAT32
  1968.              MOV      ES,BX
  1969.              MOV      ES:_PSP,AX
  1970. ; check to see if we are running on a 386/486
  1971.              XOR      AX,AX
  1972.              PUSH     AX
  1973.              POPF
  1974.              PUSHF
  1975.              POP      AX
  1976.              AND      AX,0F000H
  1977.              CMP      AX,0F000H
  1978.              JNZ      SHORT NOT86
  1979. NOT386:
  1980.              MOV      DX, OFFSET NOT386M
  1981. NOT386EXIT:
  1982.              MOV      AH,9
  1983.              INT      21H
  1984.              MOV      AX,4C80H
  1985.              INT      21H          ; exit
  1986. NOT86:
  1987.              MOV      AX,0F000H
  1988.              PUSH     AX
  1989.              POPF
  1990.              PUSHF
  1991.              POP      AX
  1992.              AND      AX,0F000H
  1993.              JZ       SHORT NOT386
  1994. ; If we got here we are on an 80386.
  1995. ; Check PM flag
  1996.              SMSW     AX
  1997.              AND      AX,1         ; are we in protected mode?
  1998.              MOV      DX,OFFSET VM86M
  1999.              JNZ      SHORT NOT386EXIT
  2000. ; OK.. we are clear to proceed
  2001.  
  2002. ; Set up new ^C, keyboard and Critical error handlers
  2003.              MOV      AX,3509H
  2004.              INT      21H
  2005.              MOV      AX,ES
  2006.              MOV      KEYSEG,AX
  2007.              MOV      KEYOFF,BX
  2008.              MOV      AX,2509H
  2009.              MOV      DX,OFFSET REBOOT
  2010.              INT      21H
  2011.              MOV      AX,2523H
  2012.              MOV      DX,OFFSET CTRLC
  2013.              INT      21H
  2014.              MOV      AX,2524H
  2015.              MOV      DX,OFFSET CRITERR
  2016.              INT      21H
  2017. ; * Create segments
  2018.              PUSH     GDTSEG
  2019.              POP      ES
  2020.              MOV      EDX, OFFSET GDT
  2021.              MOV      EBX,CS
  2022.              SHL      EBX,4        ; calc segment base address
  2023.              MOV      ECX,0FFFFH   ; 64 K limit (don't change)
  2024.              MOV      AH,ER_CODE   ; read/exec code seg
  2025.              XOR      AL,AL        ; size
  2026.              PUSH     GDTSEG
  2027.              POP      ES
  2028.              MOV      EDX, OFFSET GDT
  2029.              MOV      SI,SEL_CODE16
  2030.              CALL     MAKE_DESC    ; make code seg (16 bit/real)
  2031.              MOV      ECX,0FFFFFH
  2032.              XOR      EBX,EBX
  2033.              MOV      SI,SEL_DATA0
  2034.              XOR      ECX,ECX
  2035.              DEC      ECX          ; ecx=ffffffff
  2036.              MOV      AL,1
  2037.              MOV      AH,RW_DATA
  2038.              CALL     MAKE_DESC    ; make data  ( 4G @ zero base )
  2039.              XOR      EAX,EAX
  2040.              INT      12H
  2041.              MOVZX    ECX,AX
  2042.              SHL      ECX,10
  2043.              LOADFREE BX           ; get free memory segment
  2044.              SUB      ECX,EBX
  2045.              DEC      ECX
  2046.              MOV      SI,SEL_FREE
  2047.              MOV      AL,1
  2048.              MOV      AH,RW_DATA
  2049.              CALL     MAKE_DESC
  2050.              XOR      EAX,EAX
  2051.              MOV      AH,88H       ; get top of extended memory
  2052.              INT      15H
  2053.              SHL      EAX,10       ; * 1024
  2054.              OR       EAX,EAX      ; any extended present?
  2055.              MOV      ECX,EAX
  2056.              JNZ      SHORT EXTPRES
  2057.              MOV      ECX,1
  2058. EXTPRES:
  2059.              DEC      ECX
  2060.              MOV      EBX,100000H
  2061.              MOV      SI,SEL_EXT   ; 0 limit segment if no ext.
  2062.              MOV      AL,1
  2063.              MOV      AH,RW_DATA
  2064.              CALL     MAKE_DESC
  2065.              XOR      EBX,EBX
  2066.              MOV      BX,SEG SEG32ENT
  2067.              SHL      EBX,4
  2068.              MOV      ECX,(SEG32END-SEG32BEG)-1
  2069.              MOV      AH,ER_CODE
  2070.              MOV      AL,1
  2071.              MOV      SI,SEL_CODE32
  2072.              CALL     MAKE_DESC    ; 32 bit code segment
  2073.              XOR      EBX,EBX
  2074.              MOV      BX,USERCODE
  2075.              SHL      EBX,4
  2076.              MOV      ECX,(USERCODEEND-USERCODEBEG)-1
  2077.              MOV      AH,ER_CODE
  2078.              MOV      AL,1
  2079.              MOV      SI,SEL_UCODE
  2080.              CALL     MAKE_DESC
  2081.              XOR      EBX,EBX
  2082.              MOV      BX,USERDATA
  2083.              SHL      EBX,4
  2084.              MOV      ECX,(USERDATAEND-USERDATABEG)-1
  2085.              MOV      AH,RW_DATA
  2086.              MOV      AL,1
  2087.              MOV      SI,SEL_UDATA
  2088.              CALL     MAKE_DESC
  2089.              XOR      EBX,EBX
  2090.              MOV      BX,SS32
  2091.              SHL      EBX,4        ; always para align stacks!
  2092.              MOV      ECX,(SSEG321-SSEG32)-1
  2093.              MOV      AH,RW_DATA   ; stack seg is data type
  2094.              MOV      AL,1
  2095.              MOV      SI,SEL_STACK
  2096.              CALL     MAKE_DESC
  2097.              XOR      EBX,EBX
  2098.              MOV      BX, SSEG
  2099.              SHL      EBX,4
  2100.              MOV      ECX,0FFFFH   ; real mode limit (don't change)
  2101.              XOR      AL,AL
  2102.              MOV      AH,RW_DATA
  2103.              MOV      SI,SEL_RDATA
  2104.              CALL     MAKE_DESC    ; 16 bit data for return to r/m
  2105.              XOR      EBX,EBX
  2106.              MOV      BX,SEG GDT
  2107.              SHL      EBX,4
  2108.              ADD      EBX,OFFSET GDT
  2109.              MOV      ECX,(GDTEND-GDT)-1
  2110.              MOV      AL,1
  2111.              MOV      AH,RW_DATA
  2112.              MOV      SI,SEL_GDT
  2113.              CALL     MAKE_DESC
  2114.              MOV      AX,500H      ; set video to page 0
  2115.              INT      10H
  2116.              MOV      AH,0FH
  2117.              INT      10H          ; get mode
  2118.              MOV      EBX,0B0000H  ; monochrome
  2119.              CMP      AL,7         ; check for mono
  2120.              JZ       SHORT VIDEOCONT
  2121.              MOV      EBX,0B8000H
  2122. VIDEOCONT:
  2123.              MOV      ECX,3999     ; limit for text page
  2124.              MOV      AL,1
  2125.              MOV      AH,RW_DATA
  2126.              MOV      SI,SEL_VIDEO
  2127.              CALL     MAKE_DESC    ; make video segment
  2128.              XOR      EBX,EBX
  2129.              MOV      BX,DAT32
  2130.              SHL      EBX,4
  2131.              MOV      ECX,(DAT32END-DAT32BEG)-1
  2132.              MOV      AH,RW_DATA
  2133.              MOV      AL,1
  2134.              MOV      SI,SEL_DATA
  2135.              CALL     MAKE_DESC
  2136.              XOR      EBX,EBX
  2137.              MOV      BX,IDTABLE
  2138.              SHL      EBX,4
  2139.              MOV      ECX,(IDTEND-IDTBEG)-1
  2140.              MOV      AH,RW_DATA
  2141.              MOV      AL,1
  2142.              MOV      SI,SEL_IDT
  2143.              CALL     MAKE_DESC
  2144.              XOR      EBX,EBX
  2145.              MOV      BX,ISR
  2146.              SHL      EBX,4
  2147.              MOV      ECX,(ISREND-ISRBEG)-1
  2148.              MOV      AH,ER_CODE
  2149.              MOV      AL,1
  2150.              MOV      SI,SEL_ICODE
  2151.              CALL     MAKE_DESC
  2152.              XOR      EBX,EBX
  2153.              MOV      BX,TSSSEG
  2154.              SHL      EBX,4
  2155. ; compute TSS length
  2156.              MOV      ECX,(TSS0END-TSS0BEG)-1
  2157.              MOV      AH,RW_DATA
  2158.              MOV      AL,1
  2159.              MOV      SI,SEL_TSS0
  2160.              CALL     MAKE_DESC
  2161.              MOV      AH,TSS_DESC
  2162.              MOV      SI,TSS0
  2163.              CALL     MAKE_DESC
  2164.              ADD      EBX,OFFSET TSS1BEG
  2165.              MOV      SI,TSS1
  2166. ; compute TSS length
  2167.              MOV      ECX,(TSS1END-TSS1BEG)-1
  2168.              CALL     MAKE_DESC
  2169.              MOV      SI,SEL_TSS1
  2170.              MOV      AH,RW_DATA
  2171.              CALL     MAKE_DESC
  2172.              MOVZX    EBX,PSP
  2173.              SHL      EBX,4
  2174.              MOV      ECX,255
  2175.              MOV      AH,RW_DATA
  2176.              MOV      AL,1
  2177.              MOV      SI,SEL_PSP
  2178.              CALL     MAKE_DESC
  2179.              PUSH     ES
  2180.              MOV      AX,PSP
  2181.              MOV      ES,AX
  2182.              XOR      EBX,EBX
  2183.              MOV      BX,ES:[2CH]
  2184.              MOV      AX,BX
  2185.              SHL      EBX,4
  2186.              DEC      AX
  2187.              MOV      ES,AX
  2188.              XOR      ECX,ECX
  2189.              MOV      CX,ES:[3]
  2190.              SHL      ECX,4
  2191.              DEC      ECX          ; get limit
  2192.              MOV      SI,SEL_ENV
  2193.              POP      ES
  2194.              MOV      AL,1
  2195.              MOV      AH,RW_DATA
  2196.              CALL     MAKE_DESC    ; make envrioment segment
  2197.  
  2198. ; turn on A20
  2199.              MOV      AL,1
  2200.              CALL     SETA20
  2201.              CLI                   ; no interrupts until prot mode
  2202.              MOV      SSEGSAV,SS
  2203. ; save sp for triumphant return to r/m
  2204.              MOV      SOFFSAV,SP
  2205.              SIDT     IDTSAV
  2206.              LIDT     XZRO         ; save and load IDT
  2207.              XOR      EBX,EBX
  2208.              MOV      BX,SEG GDT
  2209.              SHL      EBX,4
  2210.              ADD      EBX,OFFSET GDT
  2211.              MOV      TEMD,EBX
  2212.              LGDT     TEMP         ; set up GDT
  2213.              MOV      EAX,CR0
  2214.              OR       EAX,1        ; switch to prot mode!
  2215.              MOV      CR0,EAX
  2216. ; jump to load CS and flush prefetch
  2217.              JMPABS   SEL_CODE16,PROT1
  2218.  
  2219. PROT1:
  2220.              OPSIZ
  2221.              JMPABS32 SEL_CODE32,SEG32ENT
  2222.  
  2223.  
  2224.  
  2225. ; Jump here to return to real mode DOS.
  2226. ; If desired AL can be set to a DOS exit code
  2227. BACK16       LABEL    FAR
  2228.              MOV      BL,AL        ; save exit code
  2229.              CLI
  2230.              XOR      EAX,EAX
  2231.              MOV      DR7,EAX      ; turn off debug (just in case)
  2232. ; restore stack
  2233.              LSS      ESP,FWORD PTR CS:LOAD16
  2234.              MOV      AX,SEL_RDATA
  2235.              MOV      DS,AX
  2236.              MOV      ES,AX
  2237.              MOV      FS,AX
  2238.              MOV      GS,AX
  2239.              MOV      EAX,CR0
  2240. ; return to real mode
  2241.              AND      EAX,07FFFFFF2H
  2242.              MOV      CR0,EAX
  2243. ; jump to load CS and clear prefetch
  2244.              JMPABS   CSEG,NEXTREAL
  2245. NEXTREAL     LABEL    FAR
  2246.              MOV      AX,CS
  2247.              MOV      DS,AX
  2248.              LIDT     IDTSAV       ; restore old IDT 0(3ff)
  2249.              IN       AL,21H
  2250.              MOV      INTM,AL
  2251. ; reprogram PIC's
  2252. IF           ATCLASS
  2253.              IN       AL,0A1H
  2254.              MOV      INTMAT,AL
  2255.              MOV      AL,11H
  2256.              OUT      0A0H,AL
  2257.              OUT      20H,AL
  2258.              IDELAY
  2259.              MOV      AL,70H
  2260.              OUT      0A1H,AL
  2261.              MOV      AL,8
  2262.              OUT      21H,AL
  2263.              IDELAY
  2264.              MOV      AL,2
  2265.              OUT      0A1H,AL
  2266.              MOV      AL,4
  2267.              OUT      21H,AL
  2268.              IDELAY
  2269.              MOV      AL,1
  2270.              OUT      0A1H,AL
  2271.              OUT      21H,AL
  2272.              IDELAY
  2273.              MOV      AL,INTMAT
  2274.              OUT      0A1H,AL
  2275.              MOV      AL,INTM
  2276.              OUT      21H,AL
  2277.  
  2278. ELSE
  2279.  
  2280.              MOV      AL,13H
  2281.              OUT      20H,AL
  2282.              MOV      AL,8
  2283.              OUT      21H,AL
  2284.              INC      AL
  2285.              OUT      21H,AL
  2286.              MOV      AL,INTM
  2287.              OUT      21H,AL
  2288. ENDIF
  2289. ; clean up to go back to DOS
  2290.              LSS      SP,DWORD PTR SOFFSAV
  2291.              STI                   ; resume interupt handling
  2292. ; turn a20 back off
  2293.              XOR      AL,AL
  2294.              CALL     SETA20
  2295. ; restore keyboard interrupt
  2296.              MOV      DX,KEYOFF
  2297.              MOV      AX,KEYSEG
  2298.              PUSH     DS
  2299.              MOV      DS,AX
  2300.              MOV      AX,2509H
  2301.              INT      21H
  2302.              POP      DS
  2303.              MOV      AH,4CH       ; blow this joint!
  2304.              MOV      AL,BL        ; get return code
  2305.              INT      21H          ; return to the planet of MSDOS
  2306. START        ENDP
  2307.  
  2308.  
  2309. ; Routine to control A20 line
  2310. ; AL=1 to turn A20 on (enable)
  2311. ; AL=0 to turn A20 off (disable)
  2312. ; returns ZF=1 if error; AX destroyed
  2313. IF           ATCLASS
  2314. SETA20       PROC     NEAR
  2315.              PUSH     CX
  2316.              MOV      AH,0DFH      ; A20 On
  2317.              OR       AL,AL
  2318.              JNZ      SHORT A20WAIT1
  2319.              MOV      AH,0DDH      ; A20 Off
  2320. A20WAIT1:
  2321.              CALL     KEYWAIT
  2322.              JZ       SHORT A20ERR
  2323.              MOV      AL,0D1H
  2324.              OUT      64H,AL
  2325.              CALL     KEYWAIT
  2326.              MOV      AL,AH
  2327.              OUT      60H,AL
  2328.              CALL     KEYWAIT
  2329.              JZ       SHORT A20ERR
  2330.              MOV      AL,0FFH
  2331.              OUT      64H,AL
  2332.              CALL     KEYWAIT
  2333. A20ERR:      POP      CX
  2334.              RET
  2335. SETA20       ENDP
  2336.  
  2337. ; Wait for keyboard controller ready. Returns ZF=1 if timeout
  2338. ; destroys CX and AL
  2339. KEYWAIT      PROC     NEAR
  2340.              XOR      CX,CX        ; maximum time out
  2341. KWAITLP:
  2342.              DEC      CX
  2343.              JZ       SHORT KEYEXIT
  2344.              IN       AL,64H
  2345.              AND      AL,2
  2346.              JNZ      KWAITLP
  2347. KEYEXIT:     OR       CX,CX
  2348.              RET
  2349. KEYWAIT      ENDP
  2350.  
  2351. ELSE
  2352. ; INBOARD PC Code for A20
  2353. SETA20       PROC     NEAR
  2354.              OR       AL,AL
  2355.              MOV      AL,0DFH
  2356.              JNZ      A20SET
  2357.              MOV      AL,0DDH
  2358. A20SET:      OUT      60H,AL
  2359.              OR       AL,AL        ; make sure ZF is set for
  2360.              RET                   ; compatibilty with AT routines
  2361. SETA20       ENDP
  2362. ENDIF
  2363.  
  2364.  
  2365. ; This routine makes a descriptor
  2366. ; ebx=base
  2367. ; ecx=limit in bytes
  2368. ; es:edx=GDT address
  2369. ; al= size (0=16bit 1=32bit)
  2370. ; ah=AR byte
  2371. ; SI=descriptor (TI & DPL not important!)
  2372. ; Auto sets and calculates G and limit
  2373. MAKE_DESC    PROC     NEAR
  2374.              PUSHAD
  2375.              MOVZX    ESI,SI
  2376.              SHR      SI,3         ; adjust to slot #
  2377.              SHL      AL,6         ; shift size to right bit position
  2378.              CMP      ECX,0FFFFFH  ; see if you need to set G bit
  2379.              JBE      SHORT OKLIMR
  2380.              SHR      ECX,12       ; div by 4096
  2381.              OR       AL,80H       ; set G bit
  2382. OKLIMR:      MOV      ES:[EDX+ESI*8],CX
  2383.              SHR      ECX,16
  2384.              OR       CL,AL
  2385.              MOV      ES:[EDX+ESI*8+6],CL
  2386.              MOV      ES:[EDX+ESI*8+2],BX
  2387.              SHR      EBX,16
  2388.              MOV      ES:[EDX+ESI*8+4],BL
  2389.              MOV      ES:[EDX+ESI*8+5],AH
  2390.              MOV      ES:[EDX+ESI*8+7],BH
  2391.              POPAD
  2392.              RET
  2393. MAKE_DESC    ENDP
  2394.  
  2395. ; This is the routine that disables ^C interrupts
  2396. ; You could place your own code here if desired
  2397. ; NOTE: THIS IS VM86 CODE!
  2398. CTRLC        PROC     FAR
  2399.              PUSH     DS
  2400.              PUSH     AX
  2401.              MOV      AX,DAT32
  2402.              MOV      DS,AX
  2403.              ASSUME   DS:DAT32
  2404.              MOV      AL,1
  2405.              MOV      BREAKKEY,AL  ; set flag
  2406.              POP      AX
  2407.              POP      DS
  2408.              IRET
  2409. CTRLC        ENDP
  2410.  
  2411. ; Reboot handler (VM86 code)
  2412. REBOOT       PROC     FAR
  2413.              STI
  2414.              PUSH     AX
  2415.              IN       AL,60H
  2416.              CMP      AL,53H       ; delete key?
  2417.              JNZ      SHORT NOREBOOT
  2418.              XOR      AX,AX
  2419.              PUSH     DS
  2420.              MOV      DS,AX
  2421.              MOV      AL,DS:[417H] ; get shift status
  2422.              POP      DS
  2423.              TEST     AL,8         ; check for cntl/alt
  2424.              JZ       SHORT NOREBOOT
  2425.              TEST     AL,4
  2426.              JZ       SHORT NOREBOOT
  2427. ; If detected a ^ALT-DEL then eat it and return
  2428.              IN       AL,61H
  2429.              MOV      AH,AL
  2430.              OR       AL,80H
  2431.              OUT      61H,AL
  2432.              MOV      AL,AH
  2433.              OUT      61H,AL
  2434.              MOV      AL,20H
  2435.              OUT      20H,AL
  2436.              POP      AX
  2437.              IRET
  2438. ; not a ^ALT-DEL, resume normal keyboard handler
  2439. NOREBOOT:    POP      AX
  2440.              JMP      CS:[KEYCHAIN]
  2441. REBOOT       ENDP
  2442.  
  2443. ; Critical error handler (always fail/ignore)
  2444. CRITERR      PROC     FAR
  2445.              PUSH     DS
  2446.              PUSH     DAT32
  2447.              POP      DS
  2448.              ASSUME   DS:DAT32
  2449.              MOV      CRITAX,AX
  2450.              MOV      AL,1
  2451.              MOV      CRITICAL,AL
  2452.              MOV      CRITDI,DI
  2453.              MOV      CRITBP,BP
  2454.              MOV      CRITSI,SI
  2455. IF           DOS      LT 3
  2456.              XOR      AL,AL
  2457. ELSE
  2458.              MOV      AL,3
  2459. ENDIF
  2460.              POP      DS
  2461.              IRET
  2462. CRITERR      ENDP
  2463.  
  2464. LAST16       EQU      $
  2465. CSEG         ENDS
  2466.  
  2467.  
  2468.  
  2469. [Example 1: A simple PROT program.]
  2470.  
  2471.  
  2472. File: USER.INC
  2473. ; SET UP EMPTY DATA SEGMENT
  2474.           NODATA
  2475.  
  2476. ; SET UP CODE SEGMENT - PROGRAM RETURNS TO DOS
  2477.           PROT_CODE
  2478. USER      PROC NEAR
  2479.           BACK2DOS
  2480. USER      ENDP
  2481.           PROT_CODE_END
  2482.  
  2483.  
  2484.  
  2485. [Example 2: DOS and PROT code fragments to print a message using
  2486. DOS service 9.]
  2487.  
  2488.  
  2489. Real Mode Program
  2490. REALPGM   PROC
  2491.           MOV AX,SEG STACKAREA
  2492.           MOV SS,AX
  2493.           MOV SP,OFFSET STACKAREA        ; SET UP STACK
  2494.           MOV AX,SEG DATSEG
  2495.           MOV DS,AX                      ; SET UP DATA SEGMENT
  2496.           MOV DX,OFFSET MESSAGE          ; LOAD POINTER TO MESSAGE
  2497.           MOV AH,9
  2498.           INT 21H                        ; PRINT MESSAGE
  2499.           MOV AH,4CH
  2500.           INT 21H                        ; RETURN TO DOS
  2501. REALPGM   ENDP
  2502.  
  2503.  
  2504.  
  2505. PROT Equivalent
  2506. USER      PROC
  2507.           PROT_STARTUP                   ; SET UP STACK/DS
  2508.           MOV AX,21H
  2509.           MOV PINTFRAME.VMINT,EAX
  2510.           MOV EDX,OFFSET MESSAGE         ; LOAD POINTER TO MESSAGE
  2511.           MOV AH,9
  2512.           MOV EBX,OFFSET PINTFRAME
  2513.           VM86CALL                       ; PRINT MESSAGE
  2514.           BACK2DOS                       ; RETURN TO DOS
  2515. USER      ENDP
  2516.  
  2517.  
  2518.  
  2519.  
  2520. [Example 3: Maintaining the caller's flags on  the  stack  when 
  2521. returning in protected mode.]
  2522.  
  2523. MOV EAX,25H
  2524.      MOV PINTFRAME.VMINT,EAX
  2525.      PUSHF                     ; (Or PUSHFD)
  2526.      VM86CALL                  ; Call INT 25 or 26
  2527.        .
  2528.        .
  2529.  
  2530.  
  2531.  
  2532. [Example 4: 32-bit offset generation problems]
  2533.  
  2534.  .386P
  2535.  SEGMENT   EXAMPLE PARA 'CODE32' USE32
  2536.           .
  2537.  BACKWARD:
  2538.           .
  2539.           .
  2540.           .
  2541.           CMP EBX,EAX     
  2542.           JA FORWARD           ; This jump is OK
  2543.           JB BACKWARD          ; This jump is improperly assembled
  2544.           .
  2545.           .
  2546.           .
  2547. FORWARD:
  2548.  
  2549.  
  2550. [Example 5: QISR code for the VM86 mode segment
  2551. qisr segment para 'CODE16' use16]
  2552.  
  2553.           assume cs:qisr
  2554.      qiret:
  2555.           push 0
  2556.           push 0
  2557.           push 0
  2558.           iret
  2559.      qisr ends
  2560.  
  2561.  
  2562. [Figure 1: Parameter block for call86 routine.]
  2563.  
  2564. Address                                   Member name
  2565.  
  2566. BLOCK+0        |------------------------------------|    VMSEGFLAG
  2567.                | Segment register flag (see text)   |
  2568. BLOCK+4        |------------------------------------|    VMINT
  2569.                | Interrupt number                   |
  2570. BLOCK+8        |------------------------------------|    VMFLAGS
  2571.                | EFLAGS                             |
  2572. BLOCK+12       |------------------------------------|    VMESP
  2573.                | ESP                                |
  2574. BLOCK+16       |------------------------------------|    VMSS
  2575.                | SS                                 |
  2576. BLOCK+20       |------------------------------------|    VMES
  2577.                | ES                                 |
  2578. BLOCK+24       |------------------------------------|    VMDS
  2579.                | DS                                 |
  2580. BLOCK+28       |------------------------------------|    VMFS
  2581.                | FS                                 |
  2582. BLOCK+32       |------------------------------------|    VMGS
  2583.                | GS                                 |
  2584. BLOCK+36       |------------------------------------|    VMEBP
  2585.                | EBP                                |
  2586. BLOCK+40       |------------------------------------|    VMEBX
  2587.                | EBX                                |
  2588.                |------------------------------------|
  2589.  
  2590.  
  2591.  
  2592. [Figure 2: Batch file used to compile a PROT program]
  2593.  
  2594. echo off
  2595. if X%1==X goto :errexit
  2596. if NOT X%2==X goto :errexit
  2597. masm /DPROGRAM=%1 PROT.ASM,%1.OBJ,%1.LST;
  2598. if ERRORLEVEL 1 goto :exit
  2599. link %1;
  2600. goto :exit
  2601. :errexit
  2602. echo PMASM - An MASM driver for the PROT 386 DOS Extender
  2603. echo usage: PMASM progname
  2604. echo        Assembles the file progname.pm into progname.exe
  2605. echo        The PROT system is copyright (C), 1989 by Al Williams.
  2606. echo        Please see the file "PROT.ASM" for more details.
  2607. :exit
  2608.  
  2609.  
  2610.  
  2611. [Figure 3: PROT interrupt/breakpoint display]
  2612.  
  2613. ES=0040      DS=0090      FS=0010      GS=0038
  2614. EDI=00000000 ESI=00000000 EBP=00000000 ESP=00000FF0 EBX=00000000
  2615. EDX=00000000 ECX=00000000 EAX=00000000 INT=03 TR=0070
  2616. Stack Dump:
  2617. 0000002B 00000088 00000202
  2618.  
  2619.  
  2620.  
  2621.  
  2622. [Figure 4: Problem cases associated with software interrupts]
  2623.  
  2624.  
  2625. Case 1: Normal INT/IRET
  2626.             ...
  2627.  
  2628.           INT 10H         ; perform interrupt
  2629.             ...
  2630.      ISR:                 ; Interrupt 10H service routine
  2631.             ...
  2632.           IRET
  2633.  
  2634.  
  2635. Case 2: INT/RETF 2
  2636.             ...
  2637.  
  2638.           INT 10H         ; perform interrupt
  2639.             ...
  2640.      ISR:                 ; Interrupt 10H service routine
  2641.             ...
  2642.  
  2643.           RETF 2
  2644.  
  2645.  
  2646. Case 3: INT/RETF (only used by INT 25H and 26H)
  2647.             ...
  2648.  
  2649.           INT 10H         ; perform interrupt
  2650.             ...
  2651.      ISR:                 ; Interrupt 10H service routine
  2652.             ...
  2653.  
  2654.           RETF 
  2655.  
  2656.  
  2657. Case 4: PUSHF/FAR CALL
  2658.             ...
  2659.  
  2660.           PUSHF           ; simulate interrupt
  2661.           CALL FAR ISR 
  2662.             ...
  2663.  
  2664.      ISR:                 ;Interrupt 10H service routine            
  2665.             ...
  2666.  
  2667.           IRET
  2668.  
  2669.  
  2670. Case 5: PUSHF/PUSH ADDRESS/IRET
  2671.  
  2672.              ...
  2673.  
  2674.           PUSHF           ; Jump to address TARGET
  2675.           PUSH SEG TARGET
  2676.           PUSH OFFSET TARGET
  2677.           IRET
  2678.             ...
  2679.      TARGET:              ; Destination of IRET
  2680.             ...
  2681.  
  2682.  -or-
  2683.  
  2684.           PUSHF           ; Simulate interrupt
  2685.           PUSH SEG RETAD
  2686.           PUSH OFFSET RETAD
  2687.           JMP FAR ISR
  2688.      RETAD:          
  2689.             ...
  2690.  
  2691.      ISR:                 ; Interrupt routine
  2692.             ...
  2693.  
  2694.           IRET
  2695.  
  2696.  
  2697.  
  2698.  
  2699.  
  2700.